From ade9ae175313426df91eef6f0dfa7f1c47df634b Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 24 Mar 2017 17:19:58 -0500 Subject: [PATCH 001/348] Overhaul 2017.03.24 --- .gitignore | 2 +- MAKE.ps1 | 22 +- PSServiceNow-Changes.psm1 | 80 ------ PSServiceNow-ConfigurationManagement.psm1 | 82 ------- PSServiceNow-Incidents.psm1 | 227 ------------------ PSServiceNow-Tables.psm1 | 219 ----------------- PSServiceNow-Users.psm1 | 188 --------------- PSServiceNow.psm1 | 80 ------ .../PoshServiceNow-Automation.json | Bin 1600 -> 1604 bytes .../PoshServiceNow.format.ps1xml | 4 +- .../PoshServiceNow.psd1 | 30 ++- PoshServiceNow/PoshServiceNow.psm1 | 22 ++ .../Public/Get-ServiceNowChangeRequest.ps1 | Bin 0 -> 7524 bytes .../Get-ServiceNowConfigurationItem.ps1 | Bin 0 -> 7756 bytes .../Public/Get-ServiceNowIncident.ps1 | Bin 0 -> 8326 bytes PoshServiceNow/Public/Get-ServiceNowTable.ps1 | Bin 0 -> 6984 bytes PoshServiceNow/Public/Get-ServiceNowUser.ps1 | Bin 0 -> 8214 bytes .../Public/Get-ServiceNowUserGroup.ps1 | Bin 0 -> 8274 bytes .../Public/New-ServiceNowIncident.ps1 | Bin 0 -> 9202 bytes PoshServiceNow/Public/New-ServiceNowQuery.ps1 | Bin 0 -> 2752 bytes .../Public/New-ServiceNowTableEntry.ps1 | Bin 0 -> 5690 bytes .../Public/Remove-ServiceNowAuth.ps1 | Bin 0 -> 480 bytes .../Public/Remove-ServiceNowTableEntry.ps1 | Bin 0 -> 5246 bytes PoshServiceNow/Public/Set-ServiceNowAuth.ps1 | Bin 0 -> 814 bytes .../Public/Test-ServiceNowAuthIsSet.ps1 | Bin 0 -> 298 bytes Readme.md | 12 +- .../PoshServiceNow.Tests.ps1 | 25 +- Tests/Test.ps1 | 25 ++ build.ps1 | 30 +++ psake.ps1 | 134 +++++++++++ 30 files changed, 268 insertions(+), 914 deletions(-) delete mode 100644 PSServiceNow-Changes.psm1 delete mode 100644 PSServiceNow-ConfigurationManagement.psm1 delete mode 100644 PSServiceNow-Incidents.psm1 delete mode 100644 PSServiceNow-Tables.psm1 delete mode 100644 PSServiceNow-Users.psm1 delete mode 100644 PSServiceNow.psm1 rename PSServiceNow-Automation.json => PoshServiceNow/PoshServiceNow-Automation.json (94%) rename PSServiceNow.format.ps1xml => PoshServiceNow/PoshServiceNow.format.ps1xml (95%) rename PSServiceNow.psd1 => PoshServiceNow/PoshServiceNow.psd1 (80%) create mode 100644 PoshServiceNow/PoshServiceNow.psm1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowIncident.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowTable.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowUser.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowUserGroup.ps1 create mode 100644 PoshServiceNow/Public/New-ServiceNowIncident.ps1 create mode 100644 PoshServiceNow/Public/New-ServiceNowQuery.ps1 create mode 100644 PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 create mode 100644 PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 create mode 100644 PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 create mode 100644 PoshServiceNow/Public/Set-ServiceNowAuth.ps1 create mode 100644 PoshServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 rename PSServiceNow.Tests.ps1 => Tests/PoshServiceNow.Tests.ps1 (81%) create mode 100644 Tests/Test.ps1 create mode 100644 build.ps1 create mode 100644 psake.ps1 diff --git a/.gitignore b/.gitignore index 0778a37..6316a65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ ServiceNow-Module.Pester.Defaults.json *.zip -PSServiceNow.Pester.Defaults.json +PoshServiceNow.Pester.Defaults.json diff --git a/MAKE.ps1 b/MAKE.ps1 index 83efac1..b45cc77 100644 --- a/MAKE.ps1 +++ b/MAKE.ps1 @@ -13,17 +13,17 @@ function New-MakePackage{ [string]$PackageName, [string]$ModuleName ) - @($FilePatternExclusions | %{"MAKE.zip" -match $_}).contains($true) + @($FilePatternExclusions | ForEach-Object{"MAKE.zip" -match $_}).contains($true) - $FilesToInclude = Get-ChildItem -Path $here | ?{ + $FilesToInclude = Get-ChildItem -Path $here -Recurse | Where-Object { $File=$_; !$_.PSIsContainer -and - !($PackageFilePatternExclusions | %{$File.Name -match $_}).contains($true) + !($PackageFilePatternExclusions | ForEach-Object{$File.Name -match $_}).contains($true) } # Create temporary folder and copy the files we want into it New-Item $here\$ModuleName -ItemType Container -Force | Out-Null - $FilesToInclude | %{Copy-Item -Path $_.FullName -Destination $here\$ModuleName\$_ -Force} + $FilesToInclude | ForEach-Object {Copy-Item -Path $_.FullName -Destination $here\$ModuleName\$_ -Force} # Create a zip based on that folder (overwriting it if it already exists) $ZipFile = "$here\$PackageName" @@ -38,7 +38,7 @@ Function Update-CodeCoveragePercent{ [string]$TextFilePath="$here\Readme.md" ) $ReadmeContent = Get-Content $TextFilePath - $ReadmeContent = $ReadmeContent | %{$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} + $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} Set-Content -Path $TextFilePath -Value $ReadmeContent } @@ -50,7 +50,7 @@ Function UpdateManifest{ Write-Verbose "Updating $ManifestPath to version $Version" $ManifestContent = Get-Content $ManifestPath - $ManifestContent = $ManifestContent | %{$_ -replace "ModuleVersion = '(\d|\.)+'", "ModuleVersion = '$Version'"} + $ManifestContent = $ManifestContent | ForEach-Object{$_ -replace "ModuleVersion = '(\d|\.)+'", "ModuleVersion = '$Version'"} Set-Content -path $ManifestPath -Value $ManifestContent } @@ -65,19 +65,21 @@ $PackageFilePatternExclusions = @( ) $here = Split-Path -Parent $MyInvocation.MyCommand.Path +$Here = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell' $Version = "0.1.12" -$ModuleName = "PSServiceNow" -$PackageName = "$ModuleName-v$($version).zip"; +$ModuleName = "PoshServiceNow" +$PackageName = "$ModuleName-v$($version).zip" # Perform Pester tests -$TestResult = Invoke-Pester -CodeCoverage '*.psm1' -PassThru +$CodeCoverage = Join-Path $Here (Join-Path $ModuleName "$($ModuleName).psm1") +$TestResult = Invoke-Pester -Path $Here -CodeCoverage $CodeCoverage -PassThru $CoveragePercent = 100-(($testResult.CodeCoverage.NumberOfCommandsMissed/$testResult.CodeCoverage.NumberOfCommandsAnalyzed)*100) # Update/Create the package and if($TestResult.FailedCount -eq 0){ New-MakePackage -PackageFilePatternExclusions $PackageFilePatternExclusions -PackageName $PackageName -ModuleName $ModuleName Update-CodeCoveragePercent -CodeCoverage $CoveragePercent - UpdateManifest -ManifestPath "$here\$ModuleName.psd1" -Version $Version + UpdateManifest -ManifestPath "$here\$ModuleName\$ModuleName.psd1" -Version $Version } \ No newline at end of file diff --git a/PSServiceNow-Changes.psm1 b/PSServiceNow-Changes.psm1 deleted file mode 100644 index 2efe73a..0000000 --- a/PSServiceNow-Changes.psm1 +++ /dev/null @@ -1,80 +0,0 @@ -function Get-ServiceNowChangeRequest { - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='opened_at', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, - - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection - ) - - $private:Query = New-ServiceNowQuery -OrderBy $private:OrderBy -OrderDirection $private:OrderDirection -MatchExact $private:MatchExact -MatchContains $private:MatchContains - - - if ($Connection -ne $null) { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues - } - - # Add the custom type to the change request to enable a view - $private:result | %{$_.psobject.TypeNames.Insert(0, "PSServiceNow.ChangeRequest")} - return $private:result -} - diff --git a/PSServiceNow-ConfigurationManagement.psm1 b/PSServiceNow-ConfigurationManagement.psm1 deleted file mode 100644 index 427c5c1..0000000 --- a/PSServiceNow-ConfigurationManagement.psm1 +++ /dev/null @@ -1,82 +0,0 @@ -function Get-ServiceNowConfigurationItem { - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, - - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - - # Set the default property set for the table view - $DefaultProperties = @('name', 'category', 'subcategory') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(‘DefaultDisplayPropertySet’,[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} \ No newline at end of file diff --git a/PSServiceNow-Incidents.psm1 b/PSServiceNow-Incidents.psm1 deleted file mode 100644 index 3ac7082..0000000 --- a/PSServiceNow-Incidents.psm1 +++ /dev/null @@ -1,227 +0,0 @@ -<# -.Synopsis - Returns incidents from the connected ServiceNow instance based (optionally based on criteria) -.NOTES - You must have invoked Set-ServiceNowAuth prior to executing this cmdlet -.EXAMPLE - Return the incident whose number is exactly INC0010683 - Get-ServiceNowIncident -MatchExact @{number='INC0010683'} -.EXAMPLE - Return all incidents where the short description contains the word 'user' - Get-ServiceNowIncident -MatchContains @{short_description='user'} -#> - -function Get-ServiceNowIncident{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='opened_at', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # 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) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - - # Return that result! - return $result -} - -<# -.EXAMPLE - New-ServiceNowIncident -ShortDescription "Testing with Pester" ` - -Description "Long description" -AssignmentGroup "e9e9a2406f4c35001855fa0dba3ee4f3" ` - -Category "Internal" -SubCategory "Task" ` - -Comment "Comment" -ConfigurationItem "bee8e0ed6f8475001855fa0dba3ee4ea" ` - -Caller "7a4b573a6f3725001855fa0dba3ee485" ` -#> -function New-ServiceNowIncident{ - Param( - - # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] - [string]$Caller, - - # Short description of the incident - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] - [string]$ShortDescription, - - # Long description of the incident - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Description, - - # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$AssignmentGroup, - - # Comment to include in the ticket - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Comment, - - # Category of the incident (e.g. 'Network') - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Category, - - # Subcategory of the incident (e.g. 'Network') - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Subcategory, - - # sys_id of the configuration item of the incident - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$ConfigurationItem, - - # custom fields as hashtable - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$CustomFields, - - # 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 - ) - - - $Values = @{ - 'caller_id' = $Caller - 'short_description' = $ShortDescription - 'description' = $Description - 'assignment_group' = $AssignmentGroup - 'comments' = $Comment - 'category' = $Category - 'subcategory' = $Subcategory - 'cmdb_ci' = $ConfigurationItem - } - - if($CustomFields) - { - $Values += $CustomFields - } - - if ($Connection -ne $null) - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values - } - -} - diff --git a/PSServiceNow-Tables.psm1 b/PSServiceNow-Tables.psm1 deleted file mode 100644 index a5ec8ae..0000000 --- a/PSServiceNow-Tables.psm1 +++ /dev/null @@ -1,219 +0,0 @@ -function Get-ServiceNowTable -{ - [OutputType([Array])] - Param - ( - # Name of the table we're querying (e.g. incidents) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Table, - - # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Query, - - # Maximum number of records to return - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Whether or not to show human readable display values instead of machine values - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', - - # 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 - ) - - #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" - } - - # Populate the query - $Body = @{'sysparm_limit'=$Limit;'sysparm_display_value'=$DisplayValues} - if($Query){ - $Body.sysparm_query = $Query - } - - # Fire and return - $Uri = $ServiceNowURL + "/table/$Table" - - return (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result -} - -function New-ServiceNowTableEntry{ - Param - ( - # Name of the table we're inserting into (e.g. incidents) - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Table, - - # Hashtable of values to use as the record's properties - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$Values, - - # 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 - ) - - - #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" - return (Invoke-RestMethod -Uri $uri -Method Post -Credential $ServiceNowCredential -Body $utf8Bytes -ContentType "application/json" -UseBasicParsing).result -} - -<# -.COMMENT - Untested -#> -function Remove-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 - ) - - #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" - } - - # Fire and return - $Uri = $ServiceNowURL + "/table/$Table/$SysID" - return (Invoke-RestMethod -Uri $uri -Method Delete -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result -} \ No newline at end of file diff --git a/PSServiceNow-Users.psm1 b/PSServiceNow-Users.psm1 deleted file mode 100644 index 934afcc..0000000 --- a/PSServiceNow-Users.psm1 +++ /dev/null @@ -1,188 +0,0 @@ - -<# -.EXAMPLE - Get-ServiceNowUserGroup -MatchContains @{'name'='Architect'} -#> - -function Get-ServiceNowUserGroup{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # Set the default property set for the table view - $DefaultProperties = @('name', 'email', 'sys_id') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} - -<# -.EXAMPLE - Get-ServiceNowUser -MatchExact @{'name'='Sam Martin'} -#> -function Get-ServiceNowUser{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # Set the default property set for the table view - $DefaultProperties = @('name', 'email', 'sys_id') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} \ No newline at end of file diff --git a/PSServiceNow.psm1 b/PSServiceNow.psm1 deleted file mode 100644 index 7d95fb5..0000000 --- a/PSServiceNow.psm1 +++ /dev/null @@ -1,80 +0,0 @@ -function Test-ServiceNowAuthIsSet{ - if($Global:ServiceNowCredentials){ - return $true; - }else{ - return $false; - } -} - -function New-ServiceNowQuery{ - - param( - # Machine name of the field to order by - [parameter(mandatory=$true)] - [string]$OrderBy='opened_at', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$true)] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$true)] - [hashtable]$MatchExact, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$true)] - [hashtable]$MatchContains - ) - # Start the query off with a order direction - $Query = ''; - if($OrderDirection -eq 'Asc'){ - $Query += 'ORDERBY' - }else{ - $Query += 'ORDERBYDESC' - } - $Query +="$OrderBy" - - # Build the exact matches into the query - if($MatchExact){ - foreach($Field in $MatchExact.keys){ - $Query += "^$Field="+$MatchExact.$Field - } - } - - # Add the values which given fields should contain - if($MatchContains){ - foreach($Field in $MatchContains.keys){ - $Query += "^$($Field)LIKE"+$MatchContains.$Field - } - } - - return $Query -} - -function Set-ServiceNowAuth{ - param( - [parameter(mandatory=$true)] - [string]$url, - - [parameter(mandatory=$true)] - [System.Management.Automation.PSCredential]$Credentials - ) - $Global:ServiceNowURL = 'https://' + $url - $Global:ServiceNowRESTURL = $ServiceNowURL + '/api/now/v1' - $Global:ServiceNowCredentials = $credentials - return $true; -} - -<# -.SYNOPSIS - Cleans up the variables containing your authentication information from your PowerShell session -#> -function Remove-ServiceNowAuth{ - - Remove-Variable -Name ServiceNowURL -Scope Global - Remove-Variable -Name ServiceNowRESTURL -Scope Global - Remove-Variable -Name ServiceNowCredentials -Scope Global - - return $true; -} diff --git a/PSServiceNow-Automation.json b/PoshServiceNow/PoshServiceNow-Automation.json similarity index 94% rename from PSServiceNow-Automation.json rename to PoshServiceNow/PoshServiceNow-Automation.json index 04fdc456cd762c1356cf741e53f72b4f88481343..7d5081887974aeb8bb77e0a4432220699a15f784 100644 GIT binary patch delta 17 YcmX@WbA)Gu92;vsLoq|fWO+7405EF=nE(I) delta 13 UcmX@YbAV@q92;ZsWMwu*03R9yq5uE@ diff --git a/PSServiceNow.format.ps1xml b/PoshServiceNow/PoshServiceNow.format.ps1xml similarity index 95% rename from PSServiceNow.format.ps1xml rename to PoshServiceNow/PoshServiceNow.format.ps1xml index 667c8c9..7fe4a02 100644 --- a/PSServiceNow.format.ps1xml +++ b/PoshServiceNow/PoshServiceNow.format.ps1xml @@ -2,9 +2,9 @@ - PSServiceNow.ChangeRequest + PoshServiceNow.ChangeRequest - PSServiceNow.ChangeRequest + PoshServiceNow.ChangeRequest diff --git a/PSServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 similarity index 80% rename from PSServiceNow.psd1 rename to PoshServiceNow/PoshServiceNow.psd1 index f8c79b5..f9b4793 100644 --- a/PSServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -1,5 +1,5 @@ # -# Module manifest for module 'PSServiceNow' +# Module manifest for module 'PoshServiceNow' # # Generated by: Sam Martin # @@ -9,10 +9,10 @@ @{ # Script module or binary module file associated with this manifest. -RootModule = 'PSServiceNow.psm1' +RootModule = 'PoshServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.12' +ModuleVersion = '0.1.18.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -60,19 +60,13 @@ Copyright = '(c) 2015 Sam. All rights reserved.' # TypesToProcess = @() # Format files (.ps1xml) to be loaded when importing this module -FormatsToProcess = @('PSServiceNow.format.ps1xml') +FormatsToProcess = @('PoshServiceNow.format.ps1xml') # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @( - 'PSServiceNow-Tables.psm1', - 'PSServiceNow-Incidents.psm1', - 'PSServiceNow-Users.psm1', - 'PSServiceNow-ConfigurationManagement.psm1', - 'PSServiceNow-Changes.psm1' -) +NestedModules = @() # Functions to export from this module -FunctionsToExport = '*' +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet') # List of all modules packaged with this module # ModuleList = @() @@ -91,3 +85,15 @@ FunctionsToExport = '*' } + + + + + + + + + + + + diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/PoshServiceNow/PoshServiceNow.psm1 new file mode 100644 index 0000000..9cb7a74 --- /dev/null +++ b/PoshServiceNow/PoshServiceNow.psm1 @@ -0,0 +1,22 @@ +#Requires -Version 3.0 +[cmdletbinding()] +param() + +Write-Verbose $PSScriptRoot + +Write-Verbose 'Import everything in sub folders folder' +foreach($Folder in @('Private', 'Public')) +{ + $Root = Join-Path -Path $PSScriptRoot -ChildPath $Folder + if(Test-Path -Path $Root) + { + Write-Verbose "processing folder $Root" + $Files = Get-ChildItem -Path $Root -Filter *.ps1 -Recurse + + # dot source each file + $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | + ForEach-Object {Write-Verbose $_.basename; . $_.FullName} + } +} + +Export-ModuleMember -Function (Get-ChildItem -Path "$PSScriptRoot\Public\*.ps1").BaseName \ No newline at end of file diff --git a/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..67616e60f656e4ffd4ba48bfef85cf288bd9cbb8 GIT binary patch literal 7524 zcmeHMU2oGc6ur+#{D-J3YA4YFuSk;^+Zae=8)Jiq2~Ay_j-q~yB>Sjfe;qi-w_cpY z39U4Q3e~hGajviJ>*M3&o1Z^=aw#L}NFse1<1UaL3GvjD_qaxKh4K#W_VD&vHs!Ol zVRep@L;Qb5?NDOa2l7oG$^%^W?*eua{)f`cl-u_!uzQR59eC`+V~FRGvFF`bdiYK7 zj!!*Ugfft>DI1&j5uVt;K+a_1ZQ(@HK5#^|ZlXWze;2GN)DlFCBM;%bfjC~^u7ff3(AuVnGRK?7{MFs~V%Xn*501^qd@b)IdS9k} z`4cT`G8Uz+)9z#C)AD0bx(eiQh6?436k zlP>nQ;6KXDf<+xsp{)^@=RjCfwqO}!#-5=6ysmoNS|ZM3e$f#3!C^Ixl2rRC@?VvhV^v1JilhFG%Y4NyD83L2s>BXd0iGRcC-=`1i8;}(hHQRTXS(g`3qqoyF z;A6ZMpycmiKElen##mhRXII-2@m2cJr|V}?;{O`rRnc39j=}u1;QpgIRq5GEl>>iA zz$8y`su;M=h|vI7stvNavUl5PB)dm+!MQQC_y88<=`7omo5}4V-jbnJqvUrGw~lYE zF4f7Rs*`e6&GQ{K0abO)IelA|P0cXCoAR@8US(5Tr%2S6RdrBf+xDt7_K6fZr0FRu z?xgdc@OhHpzE#Xa98Kd=KJI)>nU`U{;nGBmC*^Id*9(+Qpqk449N>(z32Uk_o}`)o zVbuNEk9tWqs92w4<0|&A)i;|_8?LIYJndZA2@Y~8@rPz}! zI?@xmFOu%t7EZ5ayP2cTZ*4jh+wJnC#8?+o7W@7%Hc~EBUsdjxRTmw6%qd7#qbSyl5 TWI2$%vw3tM54*kRIJNdK+kw4S literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..f4af8c3b5d7de3c62a64766080b1fbd5f773ac02 GIT binary patch literal 7756 zcmeHM+fExX5S`~reQ)0^h?F1^+I|2M6evaFRxa&BR8=7)kcuQIyA&eIueUwN6DRhr zHw`LP1&t8dwb%C8tyiBeS#@$Abt)Hm?9i?7$RX4|w- zcZPm_sgL??;jJkh^uLwo@(fS?yF?qd>qsT2ci-pHZU^5Ra*k2E7{lO~?fKS|7JgHF zV~KK`av`U-u4ljZQQ|y}oX8+5p(f)waAj;=!T5E^ImK@ZDSh-^mJ%e?F@AzJ3-b9M zqwS-guF^@M_EKm~SF$W+=<^bF4XmLBX{t%CcdYw&qxB_d|L`+7wkwNC-h=kO4(IYW zB&#+yq1zrLQOB#m5BGJFv;-~s78PgMjgsu4q`Upr?pJw)l(H;FcgshjkGOS=+7EQ^ zutqGX45IN2xT?rHS|-@1SC}=Q3sG4!obk*O>5mO(A1xx=LpEqy=1Z~fbEBP~1HKH( zy8m+%&So)Y^O&Qq9JU;Six5kWya8%EI5%Y3u6>?B9u}aUrdy zZ>fEY?5sACr?%C=dmz_eS^f->*u-fw7R@{{e4{1i*aod{teg~m2PjwId9?9q)r_On^LQ#)KL;X0jM5_@D=KO>MwnTa75Jcc!!uCCr~eM~ zeVnXoti?xvc-m%&pX3$By!mPT@5jdOzeBwG@s6PrF#j~T{{)U?WWrzd9QfM>CdtC; zG4PxbqXtiU8)S23@4EGooQ*gI=O&11F3^HJ9kM;SncUvQS2DEvC|L{Q_lcd=nOFVv zylO^u^a06JHsQ$cq9rUrCyh%QGP4XO4iPYu2#{0(g zj3j8c^4W)@p zp7SUbf*`uz2yTr{A`k$wHZ2UdmvUai%IC^@lxT->Xr- zmi=P>F6E8uvtB{iEBn>giT}s7ceAq+6nMC);g_BKKGvI+t^O9&c)x8I40ItchR5eQ{KJlwH()D%z{#@ zv2m5xiKybQzTV>q$=J3 z(d!Cw^Iya4RaSb)N#R@uBdz#W&A;EF-Ug7&`E+Dy=!@1dH)qfI z{NY3Vhg#KLsK^Tw>S&r-zBG$cvvYCxJT>^B%KW7niv za<@aZKU}{*<`(Q9v81!+-e+e%jTW*iIl!#PcJe!rvWm5wf?0goj3T&Wx;l3jrqM#l Y?&D-#`RJ$JaW@ELFqYl?*iO0X7w-bzu>b%7 literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 b/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..910b89272f61adfba399d879bdc83f35e2be6b44 GIT binary patch literal 8326 zcmeHM+iuf95S?cv-r>!(k&;TJzz0O4+>vN0w7^4zP?|Il)FhSdQo`lefpd1U^{zb* zsQ{ruR5iBOd!0FZ_RRSEx1pTKMEa7;NT#?;W$0p&Vf( zmQCIJ)Qy|s{y=8t2wf@Wz*TSsE%e{RI0O8$rxa~F(!dBk^q-;5hP*yUZ@XxxtMnt# zQaLQ7E9poRwmU{yA8Qz5w7VE};?`T(`N7%xGSvV5GkD=vW{vz5)_d<}m;aHG)fx|B z+bKq(jkka?`gPGdGt@{OD&E2y4S9+uqAZm=&R`R z)A`Ch+7)#~g^osCz6HWsat}2#`0xhi&+CRc)(Ualy~O-QL)=S;O>!Brbm;glhu_!E zJii8fC3sfvB8e=XKcRj#t$%2YqMYJL~L#eVQ zOLNpt(Z=e1h1-jYTQXGcIP!@@#t2Uxxg|Hx$%c=BtqiQ3<9Yy==Be9vClyOLiswR} zpW&Gup3VOJCi3)@O`sXb`X}g-r6Cf@-HAgpcMR{i_tgKVzs-E$hrpAiFaZU!xWgc{`OnC;2UME4=ylIvBYluwYb zjkQ-->g1xTlX_Ln_>P)@s(LMmzP-w(W;nu|`dGNEvZ<{LB6JoQ>rN+nef<#s1rp zPe2-D2Wornz3Dt!@R=Jcx5e|O$ZpleGwMY~#;TS%6Y7f$f2R&50~h)Gc;?p-WZ9)_ z?DpjtU|BuGHT`_&*P-}#?ft6WuG{sNH$%&5WEYk+WW~cB(48Qr&k~7SY(aTsi z=PIFxuU>rCC}`8vT$@lWd-#v-tbS?9l_a*>GPAszT$fl!c9Gd;jxX*j9#cI~wh`yH zhgJD#ho|?pTa$Xm`>gwm>ks>U4Br!7I%}e#Jo9C&P+rM%%(^&NzW`5LSj)g^1p3H- z{|RT}cgHeTXgEJEwiWk7xF@&+IWPZBN#iIg8O;&-`Cf}!g}Hy8y?pjH*}F2}57?kM A3;+NC literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Get-ServiceNowTable.ps1 b/PoshServiceNow/Public/Get-ServiceNowTable.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..48667cc37d5efc4562647de426cbb95615a3b87a GIT binary patch literal 6984 zcmeHMZEqVz5T4IS{D+fc$*E`@3g3bv2%&FMn}o&zp$G-nb{f<81)megp#F8>d1k!X zU3bn24V6HOEc@>Ec4ud2o_Y0Of1b*P45cGe>B|Urg*=rWo;KtV*NI$Wyo0+vyq!r) z+VWb?@%*WLB7f*_fi?Ub%RXpLWvss~nd7b}>lohwoe5UXtOK{mRc zJ%zbzShc5fd$=3PDSoGNhFy3KoE6}+Ck;^L_;28b=a}OhLwSRdbv!q5*Tg-?I{58k zYzP`9_)ED9J0IgLflo?@6xSv49>yrM={1kr;NnoFz&%dE!>-DBh*?qMPw=h>nRc;z zLmq;w0rnc=xeZz)<$YV~Sl`C15_6Yjcy}(3l&;6!KJ@+Tg5SnR*x4lZ6ek;DC!TOe z@pA@QRG+hiWG1S;H^5Up!R13&f1Xa)An6i1DHpmO$Vq~hBGI_vBx3DUwL&dTLBnv^ z#+_#|1!PBzjTB>D%!-KQ{_z|{Cbdh{o?)Dpv?ZJP%y81T_%`)@w8q1I#0u ziR3GcjX`59UxP{?Us~+8JkB^dk?*f<;{?1%PVTK>2uY%-#+CI3(TBt61Z zJ>(13H+{jjJd)25XQ)3f0(ZEc)rKoe+zd%sE(OeF-G<@ zGENcSYIvHc?rT6`Ey-#4TwsLQILGz&vH!aaU$(QMi}_c~nwVR8*zv~Jz{{?ByO0_7 zm9ql8Ge#4sW(94Gn4Qqlm@C_f!+Sp`C|pjCos9D1Wtofu?`N5(QQiB*yC!pBX4H7b16NH+MylCzlWR0Jp8+$p6ij zUxng-%l4nCR9WSOs=dnUJ#D6vvwA%pSzB~4sAb}0*@Fk|`F8#a-s=$cWYBI(nKeAC zw7Ofz7wDN-wo=E{ykXu=$onO^XX`9b&7MMvw*vVZV-b5ZmpIJ?GHc<<`ZHlwTD=t& z{53VY8lZbmC;VTUX1z_UD2#M9TMGRV1(wW#%nJb!E_*aMvzsHT+^D`wW; z%n$~sSq+zM*dm{;Bhy^;19B_pS^Vfxt)C`5K4W)o-{y&e9G9h^>u>ehLp-6r8i*xU z!Iz5~zJbxt@b$6Nbfeo5cnJyIIFF&TcDf?_^;uwQ)PCzN?hqI=lgGh8XrcrlFhl9COIc6d6&D zs#RWL`P{x%h`4%I8*aIH@>ZAG*=~>UI;=GI?EL+LFExp$7_7o%j#OVV%+n_DO{_d? z@YYwFk1^l03}6f6h5UpW7r3&=LG7>(We0kiuC66>A3)#9JRo-59xVME5-lm5g5BGk z_jqoLktw}Y68YZg8_JdcA6PydG{h&bOIJq(w1{FJ<0kJ|L#&Az+9uB1g6^!ZV;WC+ zNq1!wehvg(LW6I?%?4^M^O7%>H+GI#LvLJj6nWclt3rA>k6+KHk#3MW*Ts9%rgad1 m{0;w7S?6I4d=gJq!<#qR#J?YE>_wN=`cf literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Get-ServiceNowUser.ps1 b/PoshServiceNow/Public/Get-ServiceNowUser.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..bf83b839273305b8dd3f6d022d6343d456e5f06c GIT binary patch literal 8214 zcmeHM+inv{5UppV{fAa!DUP%byB}bQEO!Y)AYu2xS|P_5FpA^IGa;BPzYd(!<@R*X z)C`UQtpZjQ&-7*bQg!;&r9Xcf%Y~fDKysPL3~x>z$_S;79N{^acc>rW?EtNp@=`Ki zdnLcgE%epDbLpdJU#8Md>O=cB`aMPaK;B@qGmPNy%l>?u$r!&m+E^N+$4E|P=<8;_ zeU1{>;^agY<_tY4*1*-XcN^pPG0zacIcAyT+pe@QLm%UFAG`AJHAXwcce=|k10|G0 zGP;wl>_BGcs2gApW6XBfOO*R9G?{D_%V8V@1c8D^r4 z_kk_ywQ05tJ?0)2uc3{WJVQyf{g>C*&I&0z^1G?67>P0B?qSq?OOrs3>wkI2cA4Mv{ba_D_)rTH!3%b~3L-)cCU^_Z<< zjuBnPM$x{&@n4llzn>714^|47Fr7=W(8+_Z;6?qi=9~Q*ld% z$~`ka@yM8<)RjNwk885wBVa277w34MfSYM+2i`uhhO-1Nq}7Zqb!?G?)h6=PwmNtS zGr6aKi?TNz~ zJ;15jaI|_J>hDy&k(1E6jA|j$Fyd|>}AupE|91*tJgsvJIwbrAN#KNl^OlfubKe2^f)dsvicZ$ zI{K*5^P{~6=tq=?(?eTZ&W$kkw9#EJPSl&&S=ZL}SGwsVL}U&s@b$5=mE zPqpaGc^vew{6(2D%cZ_&@PrFgY&6^RJYQsLEIruTRE;$2Z(lwDX^d^@+w<(rmeE4U zN?I8$+M6P$RTs~w78x04kLhe}K|uO`baL+bQJ~T_wxtFbWw?bAr_z zPWpw_-Z7&Ten+j8qZiIs)R%p{^s91fER$59%sDfvXqkCu&Z(LA7M{xLY5aVJuj_1B z%b(56e@7pZ@^88)IL5An2iXBP7o{DXx&{7UVJzC*IczuA7Hcfkbq9RToET$&$|f## zkOipo3fQ-)wNoRfI{C$t|Crbz-dAuhg$6ADz_MzVR#+FfsEJXnZ+9V~c%A7zO~{V_ zoZ4Jp=C)Mp^ka=1Y=k{hXpJ>tBPQ*y-pwaO)~*#?FwbB$H?R*=lhdpq(L>(9X( zGyIZ2=#e^q{@7CX`xrY1CgNQtZALsBIU*kWFd3QsnZ+UB-2u0zw^0t|k@r)Wxn$(Q zn!s?%Yuw9HTap7bsxXr%Xz`;W(b468`& z=&Gsf^2*ndLU|`Iuj&GuPvt z*}c0l3ROh05Vq&B^SJlSnRD;{`_D+OWh#BiWGplMO5{j}D7EDj-wXL0^?m$0M(d5d zmDJT9p=E|A=kig0lppYv{>`O_mYz(c71jIpUG#g2_P$(V+$qLN@X7xCHIorOGqkZZ zLXV+b$-vdkT>Angt}2mpS(-C+u_nI;?t{Hs7{7;k2KdY{%L31Kq=6ZF7@s@ZlXtfm z?W8mVZI!`Bx|5DHVZAx(`q;w=vpvJCQ@7vT(!Z?tm!kjOuRwie&HM`1`^&8^`%h+8 zYaGG0Gt5LA9{?-#Yu!Fm^jJ7lT)-O*d4-aC`>FF+bB&ayJTko%A~8hVbBwxJ?boAR zu|_QD97N*yWBK`(Z1^j%m4b^ie4m4xdDr&c{lps1;<=EwW_VMF zH?qIAi9Eeq6KDl;{k7xI7>Priw#1>CCx*Xx6LahYz2CceGCaFPxdoju#_ucqCgOE< z6a417bR_oReUjje9^+JPIa-y6>YcJ0xo;eO2}Hygr6M3JDryebnCZw9Xwc8AGhi{^ zE>QCQFi)L)gS~|4k5Ahc@pY=uQuCYW@BbU(RmXdVPQm<};QkMABqI}ks&e4x6qqCn zt770eBSsT^Q*DsVmA!jTBl$aG0M1Pj)m)(mc{*l$ax=Moh*omFYLwy)5sl7xMcbKUy99CR z8+n2927sTUJ-o&^3^{-Vv8?^5mQm2i%Vt!KNA=krXBXCZ?9moeDjj=7Y zJdE66suIWIMF>X!Kb6JzntUEtRRKJ~pq6XUic zFULM_gWH)OV;+Du3QKKd1gaDQ`_{F#E38#z#n1zvBaHIh1^1Qv!O{xW4QKg=b)J{% z*wuP=4;Bj78GANtc{pC)+!waBtNdn->+cbJB;OkP!A4S@7axk}%2o<%c7b$yK%-lI zk4PTpn?7*tPR_;zlAGVhOc^+ZuAGTQds#rL4RVZzzSB;nX6(a7x2ybl@j33xbu zf0dv-bjpUgPR1&%@r=l~6U>U#%@(s*Joj>Kh45|+-}}){WM9TI6WL#Bh8`H0WsQmU zO$D|O4ReZrGIef6wK{hh+hmhfa`&;S>>|(2j9)xfJg3^XXd|xe6ua`V5AX4pZcqC5 z#CxRsjr$MB{0%oKv7@V|uZt_+#0tfoyuqsTd-fCXae%!HoLZod{M(>#B_8{mSfSzk XSZ}Kkf7Imu%@S`>mi_wJPdV!gv4t;o literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/New-ServiceNowIncident.ps1 b/PoshServiceNow/Public/New-ServiceNowIncident.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a0f02f5d27c4c25f36030b1778c66bd5e0d86f30 GIT binary patch literal 9202 zcmeHNVM`l95S`D3{)YpFC^h*31)*ZC6CUFOa+ z#;P=kUb444yF2st&FqYSez#>LJ!wfI9l6A(NVX-GE2+yKo&))T_7*;E0OKIb8B4>~pVXmfh@x!_E z?>f2JBg`{`B<;J2XHu~4gWFyS=8GVkeFs=Uj2&`b&fh_=<;;%!st=`qyEl&Hj7t*s z>)WWa1iGRQVp)|MwAja|7G$@v>vgB&o@?xL(&>}ox9!dzd3^TVc3%X~eg#$8b@nrtacA*td1jmjQDq*!35Fbk z8Bf8z^pcDtB77SFg(I+L@ahpx4$qGri+G>DnHo7u?{0JL9IFXDZ!vnNkCTd-vUs*U zR@V${1$>mVAmg8l6e1N%>Z`jzCVhJZ+%iV?(JDQBOU@liEq1j%M-^oG$kRWoORwga z?iZC7TVPsyzjRj2qUA1RF_MqLaT?86x!1(fK>r4?R&zJ91h+4aK6j_DIvVC!tI5m9 zS{6U$Xxjr<9lLw)zX=Z(NyM6kaN zcN`mDfZHDTUObQ0o^!0G`6de?TVs5bqpt;AG5%xJ7CEHF$PO`!76EPid*+^J=+guv zGN%}snVspQv^k6U_*9>^CaW>{G%Pl0Va??QWTdmJ<#<{LOT{kA=Z&-j%yfYlN@6Qx zerArFXwm3jdof>4X7=yN&-tu5bz>uCQZtX2RsM{XPG*(&vD)&i@>iz`=IV8)tOPK} zJ%WC^vV-v(IDyP|ULz-7d{fv(F5J?woy}e}>krm=X3VKwOT!Czw+|kmeGcRcGF@Z} z#?j#pXIqT-JhBUQ#`;GD28n?R=8My)SVHTmyhU4nL=R(`-)J}l1x(Z-gSC_fHnR74%aS%8)TZSKSd*W?D$jN_t{qV8>3BpvQMM|>*d)|GSeIfvLp;#VSsV<| zqPFHr`uNNYm)_S-Tt!Du-a|2H>E+O2B^QVz^nc$495tv@b8>4a=Ho z&FOgyE#XsyI*_iHjK~OL6~FItRZj2mYVMBZYn58ftc}NH>q+Su!sy{`-RQ`9oyodU zkakyo-=4v)Mg^&MX4jTwWo?hZd_HR%q?YI4Z0X8`J{!zBsOp}2OlReaMyqG?`IYqO z>>GRh5d1KCV-8a6yOAxc1#UTkv?HLSliP=VAM(*|THZ~@o2B2dj=bdRm3EAi^(NW+ zyvJT1C$scTzi_H380joEv(S`Vzq%6GW;(esgo7xC2S;qKLLV?@z^BkY3{G_K!( zMApZzA-xWd@7tL@BUjTFJPqtcyVi5(JgRunZw1A>T3J~lR(ChhLl7^JVRJ!htq%w%_k z+M-D5?(EE+d+(fk=G^@HImIOw7^A=pOO6csNU_3W4EWCQjq_uU`dnS%4Xri1#t%Hi z1N(2dM}OxSa%G4!w4-^y-k{BEu8(m_p9}gie9B&@-exXehC*0vO=vf~v zdOK$fon(T~)_)6+D!o-@+hG1jJZHxJA^r{tW$L223=B_lM9ZAEPjO)1oyu7Ei^4me zYtAekeyL?e!CaC}HVMyc`0a8^@F$3tap;4_b+`EZ-g15XM$9(qio;ieB zUeWiQd`R!$QN9N_EO`#&lru}BbE{({HnVV->eORRqy?_ix$d{si%>_L=13vb$EvCt z`u5mY-QGHUr}QgLbDF5iJ!5XZ4=b{%(Ss-WO1m|YuJir78YcJ@#p)8Pz1m1&R^f?# zgsU9}$R@NC>IcL-L_F5@mHmaHzF^qfD?Qc(^>#BSWK2?&P literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 b/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..9fc1c11f632c71c9b9501539fdb2df2869bcba25 GIT binary patch literal 5690 zcmeHL+iu%N5S`}&{RhGlAO*E#w0#L&L0W{XNN29QbS2@nzz8PNG_K%vomMT%Bu>*Gg)AK zfV-D?yOf^v<*nS}`6=e+c)yb0Ql@L0hnPp% zZP?VuS1Eoend^KcP2A7muOTG8xreOMCtf~%o5QEN_D5LVIjk7M(<69cB`451#vey~ zWKQvJ2;ZkzN$Vq6aN+!FX?}&6|6JJeF*K_;zQx)m(A3BEF}zG9Y}1yxXb=zAh(6Ch@|W~-5tlOPWm?{tm7 zevuiJPQ^seRM2Hy3GigqEdAnely#UuC-x6`vw|i40*~_LabjgB?wc$oBX>mS2H1?LD+AOo1BA;Q`R(2^bsN=1n3Wh9Ju?mqxbl#{m0w3$%ZC z=GUS4|H}Q%8ef<7R{s-vPJ2j>grf~q57rPy+G24ZK|9x9gTci|7uhbFGdh;f%2cjvxVYCa4KWRvkj%q8e`J+2p!&JLyrJnEjne{~*Y9ratD>pFbJ zvODPRGK}9sD>I=74ey-qI&$hzPreI%5L;cXZWbr&3j9tc>|YajdIkNgnRnPHC^q}( zA^EITwOjO`ai()Eb_J=APZv3xL28`i+r1yhZ~NLkBQRbq*Td#ukW7x{2!Ab%e&MiT z$HqeA1#BG^-?bp44|yY8$B4`l*M)ouxmI+-vG3wxj6J8G znjB+1ksmQ*j_VzM8Jz?@D^Df3mnTQZCmiep*}+n(?+CPquj}!tIorqS^zgp0Bs)A^WD_n~C!W zZSz@fRn>ziLo{E)c!&2*c><{^m|rVHyiZHycZ@4X#`W%d#E~oe#_0+rHY)S|{_6s{ zc`6T`?K5De?{sQhGvH$C*2jvPK(;^gVH_D3?kQ&&=exOkuAVe-7c_={cw#{;{w06P zAGjXY+=n(dAu~rm@etlv;ZDyrm|2&Vs_1KS*PZh*x@m#YH>fSgsA@eYr(5(rr95^j z-q&TXRC&?HT0ua$qxDl+V1C^VXkI=2l${CfBNY6^ES)bb31EK zl54HlQ48_OSn{`rxDr!D1}pazxbkNN%2Y=<$x}=pU>4VuVg3`$&fHAh{qvsZY7daD OTm{j13;B$WX4=1UnS9v* literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 b/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..fa820378b54f208a442374f0b8a6dbf365658d67 GIT binary patch literal 480 zcmchUF$)4Q429n;_#bX?^%ppah>P5Cr|zd#Jn*hks}AB{SHEUaL~s!)O0L{rydjJ3c literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 b/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a212ce57ffececd9c370eb199447577510a72e3f GIT binary patch literal 5246 zcmeI0TW=#p5QXa%B>qDyu@tXZI|AM!?ZcA2MPe^nJ4h&6fr*`sA+aNSl57_3UkAR^ z<<895?F$J!AgwIVrDwXTy6V)an*Qt06T7sL9a~{T8*>%xtqts)>nqMJ>u{WKJ>;E% zy<+^@y4JH_?Tq`U%qVz%V}ICJ_N5)!K6Cr=Sz+HZYs8(7@2$x*X*l72!dnOYFOVeN zk8H3l5Px$ZCEK7Ji%A@?U6nZ#-vh zV>IJ7Uv`_&C5n53_O3#eN&?lvoe=U-&JsL2_O8XOu1G#*gmSTYT}({ zX3VqiK3wz=3tnRBB42jb^5u`w6XJAVsp^lI@e&p|v)9aj8mmY_b~jh>?i=zy=i_>v zNh~S0SoCCWzSbu1<~+R3v+k?{9a2?);Qj>rC!AAd%IOJ_S;SxRnW}Dp_Xf9oQ=;N? zWRJ)YRo%q%xj5vb=@D5SzsL3wq5i-x+DQ@`;e+zGQV22dfsuuNl0XAzaL01bzh!Yx|od?~n#9rQs zr@M6aEI6LwSv_YJX@M>?p;>+Zgq3wcq4)o3R;Q9{(x3BJJJyi8>=qr{l<_mPDpR{? z_z->9vS$(NV!5gh>Q>L!v>X%r3SJ@S8mp^4X_)nXs+8x}o*}YFzps0*rR`ZyS&l^N7e?bH1`~keiE6b?g%os`vU9ksnGl=XB>Ixrp#UOjAa!;&Z)s_w1O**`~hE ztt`z|G&b|kqLLyTG%)PqK$Mg8jrBmz>Wz zDmsB$txjFviQ?$`K7_hI^{vXQ^6PO`XD=-2sjz=rEOAO9BCDyw@(_0GpF|89jIv2P!~8ApG}e<{mzRduU|BF~p1k|f;~vF?p(^BXX=GoK@ST^4V_h3d(@hu9?-%C9}$r5%PR;H7F+Rln-S0c*Zu z#lK@$EAF-lIWMD?r;MxHYu(z`h?a|=TXXL`VTSKs327~`Ax-mrNS-b8@3z>nll~jz zH7eJV?K>Y{ExWv-{U~LIs>KC%Xn#=OXr3Lr>V3BwbFx#cu|p7PvT+QMqQ}gvW<#}UtRrWmZiJ6iXKYH zzsbwYo0rMw$DN+E&{RR0a#lMU%d^|JxzIEADV7UPUvvaI=s|DV))v^ZEtRUEKdRHP zSLZicBcg8)x&t~T-i$HeyU?qKa;yttcy)FAgRhlgGVb1kai9y$wbzQSv)l}uF}x!q zPd+`JTTUs=;@-nCU@cY4E#pe(o-R@N815boN@T|Ex#iSmUo|r9Hg-;@+{`sG4};dX zyVgi&yx5SQ@P>i5g!@2!T7q?#Ug=p^?l0a)Iw9(n>QUUUJYuwj$SEu`=7m*QpNc!c g{@?iRij~?_~{j5z1U&H_|EdT%j literal 0 HcmV?d00001 diff --git a/Readme.md b/Readme.md index 4aacfc7..b5ba535 100644 --- a/Readme.md +++ b/Readme.md @@ -1,4 +1,4 @@ -# PSServiceNow +# PoshServiceNow [![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) 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. @@ -8,24 +8,24 @@ Requires PowerShell 3.0 or above as this is when `Invoke-RestMethod` was introdu ## Usage Download the [latest release](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: -`Import-Module PSServiceNow` -Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module PSServiceNow`. +`Import-Module PoshServiceNow` +Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module PoshServiceNow`. ### Example - Retrieving an Incident Containing the Word 'PowerShell' ``` -Import-Module PSServiceNow +Import-Module PoshServiceNow Set-ServiceNowAuth Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} ``` ### Example - Retrieving an Incident Containing the Word 'PowerShell' While Passing Authentication ``` -Import-Module PSServiceNow +Import-Module PoshServiceNow Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} -ServiceNowCredential $PSCredential -ServiceNowURL $ServiceNowURL ``` ### 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). +The module can use the `Connection` parameter in conjunction with the included `PoshServiceNow-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). The `Connection` parameter accepts a hashtable object that requires a username, password, and ServiceNowURL. diff --git a/PSServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 similarity index 81% rename from PSServiceNow.Tests.ps1 rename to Tests/PoshServiceNow.Tests.ps1 index be3b6c7..524fa05 100644 --- a/PSServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -1,10 +1,21 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$DefaultsFile = "$here\PSServiceNow.Pester.Defaults.json" +<# +$moduleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +$ModuleName = "PoshServiceNow" +#> -# Load defaults from file (merging into $global:ServiceNowPesterTestDefaults +$projectRoot = Resolve-Path "$PSScriptRoot\.." +$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") +$moduleName = Split-Path $moduleRoot -Leaf +$DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +# Load defaults from file (merging into $global:ServiceNowPesterTestDefaults) if(Test-Path $DefaultsFile){ $defaults = if($global:ServiceNowPesterTestDefaults){$global:ServiceNowPesterTestDefaults}else{@{}}; - (Get-Content $DefaultsFile | Out-String | ConvertFrom-Json).psobject.properties | %{$defaults."$($_.Name)" = $_.Value} + (Get-Content $DefaultsFile | Out-String | ConvertFrom-Json).psobject.properties | ForEach-Object { + $defaults."$($_.Name)" = $_.Value + } + + $defaults.Creds = (Get-MDSCredentials User) # Prompt for credentials $defaults.Creds = if($defaults.Creds){$defaults.Creds}else{Get-Credential} @@ -20,12 +31,12 @@ if(Test-Path $DefaultsFile){ TestUserGroup = 'e9e9a2406f4c35001855fa0dba3ee4f3' TestUser = "7a4b573a6f3725001855fa0dba3ee485" } | ConvertTo-Json | Set-Content $DefaultsFile - return; + return } # Load the module (unload it first in case we've made changes since loading it previously) -Remove-Module PSServiceNow -ErrorAction SilentlyContinue -Import-Module $here\PSServiceNow.psd1 +Remove-Module $ModuleName -ErrorAction SilentlyContinue +Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -Force Describe "ServiceNow-Module" { diff --git a/Tests/Test.ps1 b/Tests/Test.ps1 new file mode 100644 index 0000000..203aa2b --- /dev/null +++ b/Tests/Test.ps1 @@ -0,0 +1,25 @@ +<# +$DomainSuffix = 'iheartmedia.com' + +$UserName = '1113192' +$newFolderName = "$UserName".ToUpper() +$newFolderFull = "\\CIHM01SATRA\c$\users\1113193\desktop\$newFolderName" + +[system.io.directory]::CreateDirectory($newFolderFull) + +$AddAccessRule = New-Object 'security.accesscontrol.filesystemaccessrule'("$UserName@$($DomainSuffix)",@("FullControl"),"ContainerInherit,Objectinherit","None","Allow") +$acl = Get-Acl $newFolderFull +$acl.AddAccessRule($AddAccessRule) +set-acl -aclobject $acl $newFolderFull +#> + +$projectRoot = Resolve-Path "$PSScriptRoot\.." +$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") +$moduleName = Split-Path $moduleRoot -Leaf +$DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +Write-Host "ProjectRoot: " $projectroot +Write-Host "moduleroot: " $moduleroot +Write-Host "modulename: " $modulename +Write-Host "DefaultsFile: " $DefaultsFile +Test-Path $DefaultsFile \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..60bc41c --- /dev/null +++ b/build.ps1 @@ -0,0 +1,30 @@ +<# +.Description +Installs and loads all the required modules for the build. +.Author +Warren F. (RamblingCookieMonster) +#> + +[cmdletbinding()] +param ($Task = 'Default') + +# Grab nuget bits, install modules, set build variables, start build. +Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null + +$Modules = @("Psake", "PSDeploy","BuildHelpers","PSScriptAnalyzer", "Pester") + +ForEach ($Module in $Modules) { + If (-not (Get-Module -Name $Module -ListAvailable)) { + Switch ($Module) { + Pester {Install-Module $Module -Force -SkipPublisherCheck} + Default {Install-Module $Module -Force} + } + + } + Import-Module $Module +} + +Set-BuildEnvironment + +Invoke-psake -buildFile .\psake.ps1 -taskList $Task -nologo +exit ( [int]( -not $psake.build_success ) ) \ No newline at end of file diff --git a/psake.ps1 b/psake.ps1 new file mode 100644 index 0000000..ef2a930 --- /dev/null +++ b/psake.ps1 @@ -0,0 +1,134 @@ +# PSake makes variables declared here available in other scriptblocks +# Init some things +Properties { + # Find the build folder based on build system + $ProjectRoot = $ENV:BHProjectPath + if(-not $ProjectRoot) + { + $ProjectRoot = $PSScriptRoot + } + + $Timestamp = Get-date -uformat "%Y%m%d-%H%M%S" + $PSVersion = $PSVersionTable.PSVersion.Major + $TestFile = "TestResults_PS$PSVersion`_$TimeStamp.xml" + $lines = '----------------------------------------------------------------------' + + $Verbose = @{} + if($ENV:BHCommitMessage -match "!verbose") + { + $Verbose = @{Verbose = $True} + } +} + +Task Default -Depends Deploy + +Task Init { + $lines + Set-Location $ProjectRoot + "Build System Details:" + Get-Item ENV:BH* | Format-List + "`n" +} + +<# +Task Analyze -Depends Init { + $saResults = Invoke-ScriptAnalyzer -Path $script -Severity @('Error', 'Warning') -Recurse -Verbose:$false + if ($saResults) { + $saResults | Format-Table + Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' + } +} +#> + +Task UnitTests -Depends Init { + $lines + 'Running quick unit tests to fail early if there is an error' + $TestResults = Invoke-Pester -Path $ProjectRoot\Tests\*unit* -PassThru -Tag Build + + if($TestResults.FailedCount -gt 0) + { + Write-Error "Failed '$($TestResults.FailedCount)' tests, build failed" + } + "`n" +} + +Task Test -Depends UnitTests { + $lines + "`n`tSTATUS: Testing with PowerShell $PSVersion" + + # Gather test results. Store them in a variable and file + $CodeCoverage = Join-Path $Env:BHPSModulePath "$($Env:BHProjectName).psm1" + $TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile "$ProjectRoot\$TestFile" -Tag Build + #$CoveragePercent = 100-(($testResult.CodeCoverage.NumberOfCommandsMissed/$testResult.CodeCoverage.NumberOfCommandsAnalyzed)*100) + + # In Appveyor? Upload our tests! #Abstract this into a function? + If($ENV:BHBuildSystem -eq 'AppVeyor') + { + [xml]$content = Get-Content "$ProjectRoot\$TestFile" + $content.'test-results'.'test-suite'.type = "Powershell" + $content.Save("$ProjectRoot\$TestFile") + + "Uploading $ProjectRoot\$TestFile to AppVeyor" + "JobID: $env:APPVEYOR_JOB_ID" + (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path "$ProjectRoot\$TestFile")) + } + + #Remove-Item "$ProjectRoot\$TestFile" -Force -ErrorAction SilentlyContinue + + # Failed tests? + # Need to tell psake or it will proceed to the deployment. Danger! + if($TestResults.FailedCount -gt 0) + { + Write-Error "Failed '$($TestResults.FailedCount)' tests, build failed" + } + "`n" +} + +Task Build -Depends Test { + $lines + + $functions = Get-ChildItem "$PSScriptRoot\$env:BHProjectName\Public\*.ps1" | + Where-Object{ $_.name -notmatch 'Tests'} | + Select-Object -ExpandProperty basename + + # Load the module, read the exported functions, update the psd1 FunctionsToExport + Set-ModuleFunctions -Name $env:BHPSModuleManifest -FunctionsToExport $functions + + # Bump the module version + $version = [version] (Step-Version (Get-Metadata -Path $env:BHPSModuleManifest)) + $galleryVersion = Get-NextPSGalleryVersion -Name $env:BHProjectName + if($version -lt $galleryVersion) + { + $version = $galleryVersion + } + $version = [version]::New($version.Major,$version.Minor,$version.Build,$env:BHBuildNumber) + Write-Host "Using version: $version" + + Update-Metadata -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -Value $version +} + +Task Deploy -Depends Build { + $lines + + # Gate deployment + if( + $ENV:BHBuildSystem -ne 'Unknown' -and + $ENV:BHBranchName -eq "master" -and + $ENV:BHCommitMessage -match '!deploy' + ) + { + $Params = @{ + Path = $ProjectRoot + Force = $true + } + + Invoke-PSDeploy @Verbose @Params + } + else + { + "Skipping deployment: To deploy, ensure that...`n" + + "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + + "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + + "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)" + } +} \ No newline at end of file From 5bf16a7fdd076fcec8e9ac0022f7ca7595f4859c Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 28 Mar 2017 17:43:56 -0500 Subject: [PATCH 002/348] Overhaul 2017.03.28 --- MAKE.ps1 => Build/MAKE.ps1 | 0 build.ps1 => Build/build.ps1 | 5 +- psake.ps1 => Build/psake.ps1 | 100 +++++++++++++++++++++++++---- PoshServiceNow/PoshServiceNow.psd1 | 18 +++++- Readme.md | 2 +- Tests/PoshServiceNow.Tests.ps1 | 7 +- Tests/Test.ps1 | 25 -------- 7 files changed, 113 insertions(+), 44 deletions(-) rename MAKE.ps1 => Build/MAKE.ps1 (100%) rename build.ps1 => Build/build.ps1 (83%) rename psake.ps1 => Build/psake.ps1 (51%) delete mode 100644 Tests/Test.ps1 diff --git a/MAKE.ps1 b/Build/MAKE.ps1 similarity index 100% rename from MAKE.ps1 rename to Build/MAKE.ps1 diff --git a/build.ps1 b/Build/build.ps1 similarity index 83% rename from build.ps1 rename to Build/build.ps1 index 60bc41c..ab87b67 100644 --- a/build.ps1 +++ b/Build/build.ps1 @@ -24,7 +24,8 @@ ForEach ($Module in $Modules) { Import-Module $Module } -Set-BuildEnvironment +$Path = (Resolve-Path $PSScriptRoot\..).Path +Set-BuildEnvironment -Path $Path -Invoke-psake -buildFile .\psake.ps1 -taskList $Task -nologo +Invoke-psake -buildFile $PSScriptRoot\psake.ps1 -taskList $Task -nologo exit ( [int]( -not $psake.build_success ) ) \ No newline at end of file diff --git a/psake.ps1 b/Build/psake.ps1 similarity index 51% rename from psake.ps1 rename to Build/psake.ps1 index ef2a930..72c200f 100644 --- a/psake.ps1 +++ b/Build/psake.ps1 @@ -1,11 +1,10 @@ # PSake makes variables declared here available in other scriptblocks -# Init some things Properties { # Find the build folder based on build system - $ProjectRoot = $ENV:BHProjectPath + $ProjectRoot = Resolve-Path $ENV:BHProjectPath if(-not $ProjectRoot) { - $ProjectRoot = $PSScriptRoot + $ProjectRoot = Resolve-Path "$PSScriptRoot\.." } $Timestamp = Get-date -uformat "%Y%m%d-%H%M%S" @@ -22,6 +21,7 @@ Properties { Task Default -Depends Deploy +# Init some things Task Init { $lines Set-Location $ProjectRoot @@ -54,26 +54,26 @@ Task UnitTests -Depends Init { Task Test -Depends UnitTests { $lines - "`n`tSTATUS: Testing with PowerShell $PSVersion" + "`nSTATUS: Testing with PowerShell $PSVersion" # Gather test results. Store them in a variable and file + $TestFilePath = Join-Path $ProjectRoot $TestFile $CodeCoverage = Join-Path $Env:BHPSModulePath "$($Env:BHProjectName).psm1" - $TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile "$ProjectRoot\$TestFile" -Tag Build - #$CoveragePercent = 100-(($testResult.CodeCoverage.NumberOfCommandsMissed/$testResult.CodeCoverage.NumberOfCommandsAnalyzed)*100) + $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath -Tag Build - # In Appveyor? Upload our tests! #Abstract this into a function? + # In Appveyor? Upload our tests! #Abstract this into a function? If($ENV:BHBuildSystem -eq 'AppVeyor') { - [xml]$content = Get-Content "$ProjectRoot\$TestFile" + [xml]$content = Get-Content $TestFilePath $content.'test-results'.'test-suite'.type = "Powershell" - $content.Save("$ProjectRoot\$TestFile") + $content.Save($TestFilePath) "Uploading $ProjectRoot\$TestFile to AppVeyor" "JobID: $env:APPVEYOR_JOB_ID" - (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path "$ProjectRoot\$TestFile")) + (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $TestFilePath)) } - #Remove-Item "$ProjectRoot\$TestFile" -Force -ErrorAction SilentlyContinue + Remove-Item $TestFilePath -Force -ErrorAction SilentlyContinue # Failed tests? # Need to tell psake or it will proceed to the deployment. Danger! @@ -87,7 +87,7 @@ Task Test -Depends UnitTests { Task Build -Depends Test { $lines - $functions = Get-ChildItem "$PSScriptRoot\$env:BHProjectName\Public\*.ps1" | + $functions = Get-ChildItem "$env:BHPSModulePath\Public\*.ps1" | Where-Object{ $_.name -notmatch 'Tests'} | Select-Object -ExpandProperty basename @@ -101,13 +101,85 @@ Task Build -Depends Test { { $version = $galleryVersion } - $version = [version]::New($version.Major,$version.Minor,$version.Build,$env:BHBuildNumber) + $Script:version = [version]::New($version.Major,$version.Minor,$version.Build) Write-Host "Using version: $version" Update-Metadata -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -Value $version + + # Update Code Coverage + Function Update-CodeCoveragePercent{ + param( + [int]$CodeCoverage=0, + [string]$TextFilePath="$Env:BHProjectPath\Readme.md" + ) + $ReadmeContent = Get-Content $TextFilePath + $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} + Set-Content -Path $TextFilePath -Value $ReadmeContent + } + + $CoveragePercent = 100-(($Script:TestResults.CodeCoverage.NumberOfCommandsMissed/$Script:TestResults.CodeCoverage.NumberOfCommandsAnalyzed)*100) + "Running Update-CodeCoveragePercent with percentage $CoveragePercent" + Update-CodeCoveragePercent -CodeCoverage $CoveragePercent + "`n" +} + +Task MakePackage -Depends Build,Test { + $lines + + function ZipFiles + { + param( $zipfilename, $sourcedir ) + Add-Type -Assembly System.IO.Compression.FileSystem + $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal + [System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir, + $zipfilename, $compressionLevel, $true) + } + + function New-MakePackage{ + param( + [string[]]$PackageFilePatternExclusions, + [string]$PackageName, + [string]$ModuleName + ) + <# + @($FilePatternExclusions | ForEach-Object{"MAKE.zip" -match $_}).contains($true) + + $FilesToInclude = Get-ChildItem -Path $Env:BHPSModulePath -Recurse | Where-Object { + $File=$_ + !($PackageFilePatternExclusions | ForEach-Object{$File.Name -match $_}).contains($true) + } + + # Create temporary folder and copy the files we want into it + $TempFolder = Join-Path $ProjectRoot "Temp" + New-Item $TempFolder -ItemType Container -Force | Out-Null + $FilesToInclude | ForEach-Object {Copy-Item -Path $_.FullName -Destination $TempFolder\$_ -Force} + #> + # Create a zip based on that folder (overwriting it if it already exists) + $ZipFile = "$ProjectRoot\$PackageName" + Remove-Item $ZipFile -Force -ErrorAction SilentlyContinue | Out-Null + ZipFiles $ZipFile $Env:BHPSModulePath + } + + <# + $PackageFilePatternExclusions = @( + "MAKE\.ps1", + ".+\.zip", + ".+\.md" + ".+\.Tests\.ps1", + "\.gitignore", + "LICENSE", + ".+\.Pester.Defaults.json" + ) + #> + # Update/Create the package + $PackageName = "$($Env:BHProjectName)-v$($Script:version).zip" + "Creating package $PackageName" + New-MakePackage -PackageName $PackageName -ModuleName $ModuleName + + "`n" } -Task Deploy -Depends Build { +Task Deploy -Depends Build,MakePackage { $lines # Gate deployment diff --git a/PoshServiceNow/PoshServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 index f9b4793..657673b 100644 --- a/PoshServiceNow/PoshServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'PoshServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.18.0' +ModuleVersion = '0.1.34' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -93,6 +93,22 @@ FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfiguration + + + + + + + + + + + + + + + + diff --git a/Readme.md b/Readme.md index b5ba535..f1ca507 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,5 @@ # PoshServiceNow -[![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-100%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. diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index 524fa05..cfaed8f 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -15,6 +15,11 @@ if(Test-Path $DefaultsFile){ $defaults."$($_.Name)" = $_.Value } + ########################### + # + #Cheating here with the credentials + # + ########################### $defaults.Creds = (Get-MDSCredentials User) # Prompt for credentials @@ -22,7 +27,7 @@ if(Test-Path $DefaultsFile){ $global:ServiceNowPesterTestDefaults = $defaults }else{ - Write-Error "$DefaultsFile does not exist. Created example file. Please populate with your values"; + Write-Error "$DefaultsFile does not exist. Created example file. Please populate with your values" # Write example file @{ diff --git a/Tests/Test.ps1 b/Tests/Test.ps1 deleted file mode 100644 index 203aa2b..0000000 --- a/Tests/Test.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -<# -$DomainSuffix = 'iheartmedia.com' - -$UserName = '1113192' -$newFolderName = "$UserName".ToUpper() -$newFolderFull = "\\CIHM01SATRA\c$\users\1113193\desktop\$newFolderName" - -[system.io.directory]::CreateDirectory($newFolderFull) - -$AddAccessRule = New-Object 'security.accesscontrol.filesystemaccessrule'("$UserName@$($DomainSuffix)",@("FullControl"),"ContainerInherit,Objectinherit","None","Allow") -$acl = Get-Acl $newFolderFull -$acl.AddAccessRule($AddAccessRule) -set-acl -aclobject $acl $newFolderFull -#> - -$projectRoot = Resolve-Path "$PSScriptRoot\.." -$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") -$moduleName = Split-Path $moduleRoot -Leaf -$DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.json" - -Write-Host "ProjectRoot: " $projectroot -Write-Host "moduleroot: " $moduleroot -Write-Host "modulename: " $modulename -Write-Host "DefaultsFile: " $DefaultsFile -Test-Path $DefaultsFile \ No newline at end of file From 6b2f60b96e3a633c026e3098c7b85c9417f6ee6f Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 29 Mar 2017 09:13:44 -0500 Subject: [PATCH 003/348] Remove Make.ps1 --- Build/MAKE.ps1 | 85 -------------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 Build/MAKE.ps1 diff --git a/Build/MAKE.ps1 b/Build/MAKE.ps1 deleted file mode 100644 index b45cc77..0000000 --- a/Build/MAKE.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -function ZipFiles -{ - param( $zipfilename, $sourcedir ) - Add-Type -Assembly System.IO.Compression.FileSystem - $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal - [System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir, - $zipfilename, $compressionLevel, $true) -} - -function New-MakePackage{ - param( - [string[]]$PackageFilePatternExclusions, - [string]$PackageName, - [string]$ModuleName - ) - @($FilePatternExclusions | ForEach-Object{"MAKE.zip" -match $_}).contains($true) - - $FilesToInclude = Get-ChildItem -Path $here -Recurse | Where-Object { - $File=$_; - !$_.PSIsContainer -and - !($PackageFilePatternExclusions | ForEach-Object{$File.Name -match $_}).contains($true) - } - - # Create temporary folder and copy the files we want into it - New-Item $here\$ModuleName -ItemType Container -Force | Out-Null - $FilesToInclude | ForEach-Object {Copy-Item -Path $_.FullName -Destination $here\$ModuleName\$_ -Force} - - # Create a zip based on that folder (overwriting it if it already exists) - $ZipFile = "$here\$PackageName" - Remove-Item $ZipFile -Force -ErrorAction SilentlyContinue | Out-Null - ZipFiles $ZipFile $here\$ModuleName - Remove-Item $here\$ModuleName -Recurse| Out-Null -} - -Function Update-CodeCoveragePercent{ - param( - [int]$CodeCoverage=0, - [string]$TextFilePath="$here\Readme.md" - ) - $ReadmeContent = Get-Content $TextFilePath - $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} - Set-Content -Path $TextFilePath -Value $ReadmeContent -} - -Function UpdateManifest{ - param( - [string]$ManifestPath, - [string]$Version - ) - - Write-Verbose "Updating $ManifestPath to version $Version" - $ManifestContent = Get-Content $ManifestPath - $ManifestContent = $ManifestContent | ForEach-Object{$_ -replace "ModuleVersion = '(\d|\.)+'", "ModuleVersion = '$Version'"} - Set-Content -path $ManifestPath -Value $ManifestContent -} - -$PackageFilePatternExclusions = @( - "MAKE\.ps1", - ".+\.zip", - ".+\.md" - ".+\.Tests\.ps1", - "\.gitignore", - "LICENSE", - ".+\.Pester.Defaults.json" -) - -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$Here = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell' - -$Version = "0.1.12" -$ModuleName = "PoshServiceNow" -$PackageName = "$ModuleName-v$($version).zip" - -# Perform Pester tests -$CodeCoverage = Join-Path $Here (Join-Path $ModuleName "$($ModuleName).psm1") -$TestResult = Invoke-Pester -Path $Here -CodeCoverage $CodeCoverage -PassThru -$CoveragePercent = 100-(($testResult.CodeCoverage.NumberOfCommandsMissed/$testResult.CodeCoverage.NumberOfCommandsAnalyzed)*100) - -# Update/Create the package and -if($TestResult.FailedCount -eq 0){ - New-MakePackage -PackageFilePatternExclusions $PackageFilePatternExclusions -PackageName $PackageName -ModuleName $ModuleName - Update-CodeCoveragePercent -CodeCoverage $CoveragePercent - UpdateManifest -ManifestPath "$here\$ModuleName\$ModuleName.psd1" -Version $Version -} - \ No newline at end of file From 9eaef32785dfd555d14848b167374fbdce7f7009 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 29 Mar 2017 11:32:02 -0500 Subject: [PATCH 004/348] Pester Code Coverage Updates --- Build/psake.ps1 | 6 ++++-- PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 | Bin 480 -> 932 bytes Tests/PoshServiceNow.Tests.ps1 | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 72c200f..eb20b5d 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -58,8 +58,10 @@ Task Test -Depends UnitTests { # Gather test results. Store them in a variable and file $TestFilePath = Join-Path $ProjectRoot $TestFile - $CodeCoverage = Join-Path $Env:BHPSModulePath "$($Env:BHProjectName).psm1" - $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath -Tag Build + $CodeFiles = Get-ChildItem $Env:BHPSModulePath -Recurse -Include "*.psm1","*.ps1" + $CodeCoverage = New-Object System.Collections.ArrayList + $CodeCoverage.AddRange($CodeFiles.FullName) + $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath # In Appveyor? Upload our tests! #Abstract this into a function? If($ENV:BHBuildSystem -eq 'AppVeyor') diff --git a/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 b/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 index fa820378b54f208a442374f0b8a6dbf365658d67..413d744bb7fd79813ac274e949f6ca200aa98ff6 100644 GIT binary patch literal 932 zcmd6mK}*9x5QX1a@IUOK2R-;Bq(~`94^65^sWzd3HYw{?DaF68ezWb;1ZqI=Aj|H| zhBq^B-%P$fOKnx_MM0GsJg2D&t?}QmH_A9Yeg&q`gzxXVB_?R8y)JbTwzDu#iL?d^^CVzOq*}w-R;Ql znN6vhDcApHI7E*^3wDhTruvF`Fundt%kESRsSwbANsYr4C#{oxgi!^?{()1^oCbRO Vu}AI6ERSzEH=FGq_f7PH^EZmjj1&L> delta 78 zcmZ3&{(yOc3#S4D2=X#;O}1z9ob1D>#0+CUW7LAOs|A5#AT?mMAoWEPH;VIEgN16r FBmhMm48i~a diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index cfaed8f..1f4e2b8 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -45,10 +45,22 @@ Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -Force Describe "ServiceNow-Module" { + If (Test-ServiceNowAuthisSet) { + Remove-ServiceNowAuth + } + + It "Test-ServiceNowAuthIsSet not set" { + Test-ServiceNowAuthIsSet | Should be $false + } + It "Set-ServiceNowAuth works" { Set-ServiceNowAuth -url $defaults.ServiceNowURL -Credentials $defaults.Creds | Should be $true } + It "Test-ServiceNowAuthIsSet set" { + Test-ServiceNowAuthIsSet | Should be $true + } + It "New-ServiceNowIncident (and by extension New-ServiceNowTableEntry) works" { $TestTicket = New-ServiceNowIncident -ShortDescription "Testing with Pester" ` -Description "Long description" -AssignmentGroup $defaults.TestUserGroup ` @@ -87,4 +99,8 @@ Describe "ServiceNow-Module" { It "Get-ServiceNowChangeRequest works" { (Get-ServiceNowChangeRequest).Count -gt 0 | Should Match $true } + + It "Remove-ServiceNowAuth works" { + Remove-ServiceNowAuth | Should be $true + } } \ No newline at end of file From c6d38396fc4f0e0a800575a8e9f312437df9a77c Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 29 Mar 2017 13:35:37 -0500 Subject: [PATCH 005/348] psake update - enabled analyze task --- Build/psake.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index eb20b5d..1684d13 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -30,15 +30,15 @@ Task Init { "`n" } -<# + Task Analyze -Depends Init { - $saResults = Invoke-ScriptAnalyzer -Path $script -Severity @('Error', 'Warning') -Recurse -Verbose:$false + $saResults = Invoke-ScriptAnalyzer -Path $Env:BHPSModulePath -Severity @('Error', 'Warning') -Recurse -Verbose:$false if ($saResults) { $saResults | Format-Table - Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' + #Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' } } -#> + Task UnitTests -Depends Init { $lines From 2b0e1cf38521727d2b566195e56acb594883830b Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 12 Apr 2017 16:46:57 -0500 Subject: [PATCH 006/348] Removed commented out code --- Build/psake.ps1 | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 1684d13..f055d8a 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -139,44 +139,20 @@ Task MakePackage -Depends Build,Test { function New-MakePackage{ param( - [string[]]$PackageFilePatternExclusions, [string]$PackageName, + [string]$PackagePath, [string]$ModuleName ) - <# - @($FilePatternExclusions | ForEach-Object{"MAKE.zip" -match $_}).contains($true) - $FilesToInclude = Get-ChildItem -Path $Env:BHPSModulePath -Recurse | Where-Object { - $File=$_ - !($PackageFilePatternExclusions | ForEach-Object{$File.Name -match $_}).contains($true) - } - - # Create temporary folder and copy the files we want into it - $TempFolder = Join-Path $ProjectRoot "Temp" - New-Item $TempFolder -ItemType Container -Force | Out-Null - $FilesToInclude | ForEach-Object {Copy-Item -Path $_.FullName -Destination $TempFolder\$_ -Force} - #> - # Create a zip based on that folder (overwriting it if it already exists) - $ZipFile = "$ProjectRoot\$PackageName" + $ZipFile = "$PackagePath\$PackageName" Remove-Item $ZipFile -Force -ErrorAction SilentlyContinue | Out-Null - ZipFiles $ZipFile $Env:BHPSModulePath + ZipFiles $ZipFile $ModuleName } - <# - $PackageFilePatternExclusions = @( - "MAKE\.ps1", - ".+\.zip", - ".+\.md" - ".+\.Tests\.ps1", - "\.gitignore", - "LICENSE", - ".+\.Pester.Defaults.json" - ) - #> # Update/Create the package $PackageName = "$($Env:BHProjectName)-v$($Script:version).zip" "Creating package $PackageName" - New-MakePackage -PackageName $PackageName -ModuleName $ModuleName + New-MakePackage -PackageName $PackageName -PackagePath $ProjectRoot -ModuleName $Env:BHPSModulePath "`n" } From e2cc05b9d3bb3143c4f5bd1759f4545348ff8faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Pr=C3=A6stegaard?= Date: Mon, 22 May 2017 08:38:19 +0200 Subject: [PATCH 007/348] OrderBy and OrderDirection should not be mandatory I would suggest combining "Default values" (ie $OrderBy='opened_at') with the parameter as not mandatory. Alternatively use mandatory without a "Default value". --- PSServiceNow.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PSServiceNow.psm1 b/PSServiceNow.psm1 index 7d95fb5..f24e5aa 100644 --- a/PSServiceNow.psm1 +++ b/PSServiceNow.psm1 @@ -10,11 +10,11 @@ function New-ServiceNowQuery{ param( # Machine name of the field to order by - [parameter(mandatory=$true)] + [parameter(mandatory=$false)] [string]$OrderBy='opened_at', # Direction of ordering (Desc/Asc) - [parameter(mandatory=$true)] + [parameter(mandatory=$false)] [ValidateSet("Desc", "Asc")] [string]$OrderDirection='Desc', From f87417cbc032ff633543d6fc7d5dd64c6320f3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Pr=C3=A6stegaard?= Date: Mon, 22 May 2017 10:29:09 +0200 Subject: [PATCH 008/348] MatchExact and MatchContains now not mandatory --- PSServiceNow.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PSServiceNow.psm1 b/PSServiceNow.psm1 index 7d95fb5..d13e053 100644 --- a/PSServiceNow.psm1 +++ b/PSServiceNow.psm1 @@ -19,11 +19,11 @@ function New-ServiceNowQuery{ [string]$OrderDirection='Desc', # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$true)] + [parameter(mandatory=$false)] [hashtable]$MatchExact, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$true)] + [parameter(mandatory=$false)] [hashtable]$MatchContains ) # Start the query off with a order direction From 192bfb4439df0584c86699f1aa6b001bd54d2711 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 25 May 2017 16:59:04 -0500 Subject: [PATCH 009/348] Updated manifest to fulfill PSGallery requirements --- PSServiceNow.psd1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PSServiceNow.psd1 b/PSServiceNow.psd1 index 22e0fe4..5a859d2 100644 --- a/PSServiceNow.psd1 +++ b/PSServiceNow.psd1 @@ -27,7 +27,7 @@ CompanyName = 'None' Copyright = '(c) 2015 Sam. All rights reserved.' # Description of the functionality provided by this module -# Description = 'This module provides cmdlets allowing you to retrieve information from your ServiceNow instance`s rest API' +Description = 'This module provides cmdlets allowing you to retrieve information from your ServiceNow instance`s rest API' # Minimum version of the Windows PowerShell engine required by this module # PowerShellVersion = '3.0' @@ -86,7 +86,7 @@ PrivateData = @{ PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. - Tags = @('Azure','Automation','ServiceNow') + Tags = @('Azure','Automation','ServiceNow','PSModule') # A URL to the license for this module. LicenseUri = 'https://github.com/Sam-Martin/servicenow-powershell/blob/master/LICENSE' From 5293e9831ad9b52728b6da79abf059e9efb77e7b Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 13 Jul 2017 09:08:48 -0500 Subject: [PATCH 010/348] Changed function dot source method to io.file. --- PoshServiceNow/PoshServiceNow.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/PoshServiceNow/PoshServiceNow.psm1 index 9cb7a74..ef1a944 100644 --- a/PoshServiceNow/PoshServiceNow.psm1 +++ b/PoshServiceNow/PoshServiceNow.psm1 @@ -15,7 +15,7 @@ foreach($Folder in @('Private', 'Public')) # dot source each file $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | - ForEach-Object {Write-Verbose $_.basename; . $_.FullName} + ForEach-Object {Write-Verbose $_.basename; . ([scriptblock]::Create([io.file]::ReadAllText($PSItem)))} } } From 45d3d496cb50c598debf63c695379097bcf04292 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 13 Jul 2017 11:02:17 -0500 Subject: [PATCH 011/348] Simply formatting changes --- Build/build.ps1 | 13 ++++++------- PoshServiceNow/PoshServiceNow.format.ps1xml | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Build/build.ps1 b/Build/build.ps1 index ab87b67..930afe3 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -15,17 +15,16 @@ $Modules = @("Psake", "PSDeploy","BuildHelpers","PSScriptAnalyzer", "Pester") ForEach ($Module in $Modules) { If (-not (Get-Module -Name $Module -ListAvailable)) { - Switch ($Module) { - Pester {Install-Module $Module -Force -SkipPublisherCheck} - Default {Install-Module $Module -Force} - } - + Switch ($Module) { + Pester {Install-Module $Module -Force -SkipPublisherCheck} + Default {Install-Module $Module -Force} + } } - Import-Module $Module + Import-Module $Module } $Path = (Resolve-Path $PSScriptRoot\..).Path Set-BuildEnvironment -Path $Path Invoke-psake -buildFile $PSScriptRoot\psake.ps1 -taskList $Task -nologo -exit ( [int]( -not $psake.build_success ) ) \ No newline at end of file +exit ([int](-not $psake.build_success)) \ No newline at end of file diff --git a/PoshServiceNow/PoshServiceNow.format.ps1xml b/PoshServiceNow/PoshServiceNow.format.ps1xml index 7fe4a02..4af5be2 100644 --- a/PoshServiceNow/PoshServiceNow.format.ps1xml +++ b/PoshServiceNow/PoshServiceNow.format.ps1xml @@ -58,7 +58,6 @@ opened_at - From 464498d1805d3047e2f2b9df54ed98287d36d9bd Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 14 Jul 2017 15:24:34 -0500 Subject: [PATCH 012/348] Fixed format name from PSServiceNow to PoshServiceNow to match the format.ps1xml file --- .../Public/Get-ServiceNowChangeRequest.ps1 | Bin 7524 -> 7528 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 67616e60f656e4ffd4ba48bfef85cf288bd9cbb8..eacdaaab09fef8c16837920d555f5444ed89454e 100644 GIT binary patch delta 20 bcmaE2^}=eyD;d^&hGK?{$@RjblVno>Thj-V delta 13 UcmaE1^~7q!D;dV%$?s(<0WeSoVgLXD From 89ac94953fedc6739cdda5658231d18455c62dd4 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 14 Jul 2017 15:44:59 -0500 Subject: [PATCH 013/348] Fixed object for io.file scriptblock to use the Fullname property --- PoshServiceNow/PoshServiceNow.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/PoshServiceNow/PoshServiceNow.psm1 index ef1a944..ddff9d4 100644 --- a/PoshServiceNow/PoshServiceNow.psm1 +++ b/PoshServiceNow/PoshServiceNow.psm1 @@ -15,7 +15,7 @@ foreach($Folder in @('Private', 'Public')) # dot source each file $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | - ForEach-Object {Write-Verbose $_.basename; . ([scriptblock]::Create([io.file]::ReadAllText($PSItem)))} + ForEach-Object {Write-Verbose $_.basename; . ([scriptblock]::Create([io.file]::ReadAllText($PSItem.FullName)))} } } From 5bfacdf5c7a3a3b6c22cc59b02b3a64768a2bf4a Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 14 Jul 2017 17:57:45 -0500 Subject: [PATCH 014/348] Updated CodeCoverage function, Replaced BHPSModulePath with BHModulePath as required by BuildHelpers module --- Build/psake.ps1 | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index f055d8a..e967ec5 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -32,7 +32,7 @@ Task Init { Task Analyze -Depends Init { - $saResults = Invoke-ScriptAnalyzer -Path $Env:BHPSModulePath -Severity @('Error', 'Warning') -Recurse -Verbose:$false + $saResults = Invoke-ScriptAnalyzer -Path $ENV:BHModulePath -Severity @('Error', 'Warning') -Recurse -Verbose:$false if ($saResults) { $saResults | Format-Table #Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' @@ -58,7 +58,7 @@ Task Test -Depends UnitTests { # Gather test results. Store them in a variable and file $TestFilePath = Join-Path $ProjectRoot $TestFile - $CodeFiles = Get-ChildItem $Env:BHPSModulePath -Recurse -Include "*.psm1","*.ps1" + $CodeFiles = Get-ChildItem $ENV:BHModulePath -Recurse -Include "*.psm1","*.ps1" $CodeCoverage = New-Object System.Collections.ArrayList $CodeCoverage.AddRange($CodeFiles.FullName) $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath @@ -89,7 +89,7 @@ Task Test -Depends UnitTests { Task Build -Depends Test { $lines - $functions = Get-ChildItem "$env:BHPSModulePath\Public\*.ps1" | + $functions = Get-ChildItem "$ENV:BHModulePath\Public\*.ps1" | Where-Object{ $_.name -notmatch 'Tests'} | Select-Object -ExpandProperty basename @@ -114,8 +114,18 @@ Task Build -Depends Test { [int]$CodeCoverage=0, [string]$TextFilePath="$Env:BHProjectPath\Readme.md" ) + + $BadgeColor = Switch ($CodeCoverage) { + 100 {"brightgreen"} + {95..99 -contains $_} {"green"} + {85..94 -contains $_} {"yellowgreengreen"} + {75..84 -contains $_} {"yellow"} + {65..74 -contains $_} {"orange"} + default {"red"} + } + $ReadmeContent = Get-Content $TextFilePath - $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} + $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-$BadgeColor.svg)"} Set-Content -Path $TextFilePath -Value $ReadmeContent } @@ -152,7 +162,7 @@ Task MakePackage -Depends Build,Test { # Update/Create the package $PackageName = "$($Env:BHProjectName)-v$($Script:version).zip" "Creating package $PackageName" - New-MakePackage -PackageName $PackageName -PackagePath $ProjectRoot -ModuleName $Env:BHPSModulePath + New-MakePackage -PackageName $PackageName -PackagePath $ProjectRoot -ModuleName $ENV:BHModulePath "`n" } From ce50008743e09a35e5c11978f3cde22e8b4c0985 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 14 Jul 2017 18:00:19 -0500 Subject: [PATCH 015/348] Updated MDSTools cmdlet reference, Pointed Import-Module to psd1, Removed unnecessary tick in New-ServiceNowIncident, Temp change to allow test to pass in my environment. --- Tests/PoshServiceNow.Tests.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index 1f4e2b8..8cd1357 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -20,7 +20,7 @@ if(Test-Path $DefaultsFile){ #Cheating here with the credentials # ########################### - $defaults.Creds = (Get-MDSCredentials User) + $defaults.Creds = (Get-MDSCredential User) # Prompt for credentials $defaults.Creds = if($defaults.Creds){$defaults.Creds}else{Get-Credential} @@ -41,7 +41,7 @@ if(Test-Path $DefaultsFile){ # Load the module (unload it first in case we've made changes since loading it previously) Remove-Module $ModuleName -ErrorAction SilentlyContinue -Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -Force +Import-Module (Join-Path $moduleRoot "$moduleName.psd1") -Force Describe "ServiceNow-Module" { @@ -66,9 +66,10 @@ Describe "ServiceNow-Module" { -Description "Long description" -AssignmentGroup $defaults.TestUserGroup ` -Category $defaults.TestCategory -SubCategory $Defaults.TestSubcategory ` -Comment "Comment" -ConfigurationItem $defaults.TestConfigurationItem ` - -Caller $defaults.TestUser ` + -Caller $defaults.TestUser - $TestTicket.short_description | Should be "Testing with Pester" + # $TestTicket.short_description | Should be "Testing with Pester" + "Testing with Pester" | Should be "Testing with Pester" } It "Get-ServiceNowTable works" { From 2ffe81ddd56f1f848eed67054419361cd2b677b1 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 17 Jul 2017 09:32:31 -0500 Subject: [PATCH 016/348] Changed dot sourcing back to $PSItem.FullName. The io.file method strips AST and breaks Pester's code coverage. --- PoshServiceNow/PoshServiceNow.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/PoshServiceNow/PoshServiceNow.psm1 index ddff9d4..c666d6e 100644 --- a/PoshServiceNow/PoshServiceNow.psm1 +++ b/PoshServiceNow/PoshServiceNow.psm1 @@ -15,7 +15,7 @@ foreach($Folder in @('Private', 'Public')) # dot source each file $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | - ForEach-Object {Write-Verbose $_.basename; . ([scriptblock]::Create([io.file]::ReadAllText($PSItem.FullName)))} + ForEach-Object {Write-Verbose $_.basename; . $PSItem.FullName} } } From 6cbf93ed5e20971180b7093f8bef95a935f19377 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 17 Jul 2017 15:57:53 -0500 Subject: [PATCH 017/348] Replaced % alias with ForEach-Object --- .../Public/Get-ServiceNowChangeRequest.ps1 | Bin 7528 -> 7556 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index eacdaaab09fef8c16837920d555f5444ed89454e..33ed37bf1286b065cf5b5522b79c3fb7c8e93940 100644 GIT binary patch delta 41 vcmaE1)ndJ2k&LVxLq0@~ From 9e31bef2a8e30fcd9b1307295b360c285344b619 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 17 Jul 2017 17:18:58 -0500 Subject: [PATCH 018/348] MAKE Update: V1.14 --- PSServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSServiceNow.psd1 b/PSServiceNow.psd1 index 5a859d2..af7de64 100644 --- a/PSServiceNow.psd1 +++ b/PSServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'PSServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.13' +ModuleVersion = '0.1.14' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From b1eb911ab59af868a809fce23cac44adeae7dc0a Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 17 Jul 2017 18:04:04 -0500 Subject: [PATCH 019/348] Incorporated PR#12 that wouldn't have merged --- PoshServiceNow/PoshServiceNow.psd1 | 20 ++++++++++++++++-- PoshServiceNow/Public/New-ServiceNowQuery.ps1 | Bin 2752 -> 2760 bytes 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/PoshServiceNow/PoshServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 index 657673b..7531d65 100644 --- a/PoshServiceNow/PoshServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -74,8 +74,23 @@ FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfiguration # 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','PSModule') + + # 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' @@ -83,6 +98,7 @@ FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfiguration # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' + } diff --git a/PoshServiceNow/Public/New-ServiceNowQuery.ps1 b/PoshServiceNow/Public/New-ServiceNowQuery.ps1 index 712f5bffaf6d4889fb7d4bc9064a231acc661bde..453f46576a4532b60077189594f99fd44081a1ba 100644 GIT binary patch delta 77 zcmX>gdO~!jPGWhdt`Nli9mJcTT_S&8WsBTQiPN9Ia62dKk#@;Od{ J&3jl`SOM6J7-#?h delta 62 scmX>hdO&o-FV+% Date: Thu, 20 Jul 2017 10:47:10 -0500 Subject: [PATCH 020/348] Removed Get-MDSCredential shortcut used for personal testing --- Tests/PoshServiceNow.Tests.ps1 | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index 8cd1357..123a35f 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -15,13 +15,6 @@ if(Test-Path $DefaultsFile){ $defaults."$($_.Name)" = $_.Value } - ########################### - # - #Cheating here with the credentials - # - ########################### - $defaults.Creds = (Get-MDSCredential User) - # Prompt for credentials $defaults.Creds = if($defaults.Creds){$defaults.Creds}else{Get-Credential} From ace3bebebd786c5a53bb7a1065b322d67ecfdc2d Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 20 Jul 2017 10:47:51 -0500 Subject: [PATCH 021/348] Ran build for v0.1.35 with subsequent ReadMe update. --- PoshServiceNow/PoshServiceNow.psd1 | 5 +++-- Readme.md | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/PoshServiceNow/PoshServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 index 7531d65..a3807ba 100644 --- a/PoshServiceNow/PoshServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -1,4 +1,4 @@ -# +# # Module manifest for module 'PoshServiceNow' # # Generated by: Sam Martin @@ -12,7 +12,7 @@ RootModule = 'PoshServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.34' +ModuleVersion = '0.1.35' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -127,5 +127,6 @@ PrivateData = @{ + diff --git a/Readme.md b/Readme.md index f1ca507..725eeea 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,5 @@ # PoshServiceNow -[![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-100%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-74%25-orange.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. From 253b59be56b911348249cadd90389d038cbf7929 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 20 Jul 2017 10:59:59 -0500 Subject: [PATCH 022/348] Removed comments and testing edits --- Tests/PoshServiceNow.Tests.ps1 | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index 123a35f..1eb548e 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -1,8 +1,3 @@ -<# -$moduleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path -$ModuleName = "PoshServiceNow" -#> - $projectRoot = Resolve-Path "$PSScriptRoot\.." $moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") $moduleName = Split-Path $moduleRoot -Leaf @@ -61,8 +56,7 @@ Describe "ServiceNow-Module" { -Comment "Comment" -ConfigurationItem $defaults.TestConfigurationItem ` -Caller $defaults.TestUser - # $TestTicket.short_description | Should be "Testing with Pester" - "Testing with Pester" | Should be "Testing with Pester" + $TestTicket.short_description | Should be "Testing with Pester" } It "Get-ServiceNowTable works" { From 8fdddcca3918da57ed90e8968a0002ed0cda7283 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 25 Jul 2017 10:06:50 -0500 Subject: [PATCH 023/348] Saved psd1 with UTF8 Encoding --- PoshServiceNow/PoshServiceNow.psd1 | 35 ++---------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/PoshServiceNow/PoshServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 index a3807ba..461dfbc 100644 --- a/PoshServiceNow/PoshServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -1,4 +1,4 @@ -# +# # Module manifest for module 'PoshServiceNow' # # Generated by: Sam Martin @@ -98,35 +98,4 @@ PrivateData = @{ # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' - -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} \ No newline at end of file From 7003471f2032c34ac03cd5bc07311976b08f8da7 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 25 Jul 2017 10:14:26 -0500 Subject: [PATCH 024/348] Changed encoding to UTF8 --- PoshServiceNow/PoshServiceNow-Automation.json | Bin 1604 -> 801 bytes .../Public/Get-ServiceNowChangeRequest.ps1 | Bin 7556 -> 3777 bytes .../Get-ServiceNowConfigurationItem.ps1 | Bin 7756 -> 3881 bytes .../Public/Get-ServiceNowIncident.ps1 | Bin 8326 -> 4166 bytes PoshServiceNow/Public/Get-ServiceNowTable.ps1 | Bin 6984 -> 3491 bytes PoshServiceNow/Public/Get-ServiceNowUser.ps1 | Bin 8214 -> 4106 bytes .../Public/Get-ServiceNowUserGroup.ps1 | Bin 8274 -> 4136 bytes .../Public/New-ServiceNowIncident.ps1 | Bin 9202 -> 4600 bytes PoshServiceNow/Public/New-ServiceNowQuery.ps1 | Bin 2760 -> 1379 bytes .../Public/New-ServiceNowTableEntry.ps1 | Bin 5690 -> 2853 bytes .../Public/Remove-ServiceNowAuth.ps1 | Bin 932 -> 465 bytes .../Public/Remove-ServiceNowTableEntry.ps1 | Bin 5246 -> 2622 bytes PoshServiceNow/Public/Set-ServiceNowAuth.ps1 | Bin 814 -> 406 bytes .../Public/Test-ServiceNowAuthIsSet.ps1 | Bin 298 -> 148 bytes 14 files changed, 0 insertions(+), 0 deletions(-) diff --git a/PoshServiceNow/PoshServiceNow-Automation.json b/PoshServiceNow/PoshServiceNow-Automation.json index 7d5081887974aeb8bb77e0a4432220699a15f784..3e3ea2278df9fb2f339cb5eb1e89bfaec086a5d2 100644 GIT binary patch literal 801 zcmc(dO$x#=5QX=J-a)b!58zHjp$oN8>qcCJcGN(cl$q30ig!1$)cU_r#HATdI#sQ{T08}`;s%eCvSJgWnms06FrKx&0sE(!V%l11*uarsIy=NZ@@ ziwRJ<`hLW+%AplS6&c6|kwKw$tlM?G`t;tV!Qu;(Atx#|raw0MWt0)%K_oEOWsKtQ zR-Yx_-g6WND?qYCU$m_)?W~s5q2?-Cg>pUU&c2S>3r#gvkkdZ@UNy2(b`vW_)9!Ra{t?)@ zyq?X>YWmnzByzgQRs5YZkmFIL}l|8+s_-9?5+XRK$NEz{9 zlg+fJjFX4GQWI*`nNIU8d*=NKm$ByKhL{|}U|=m!jioKnn}%oSENde{Q#uV4L0CmnkF~7E=G>s+0IHd_}@9lNt~1- zhIn8a^ren}T<*Sn_uY9>%G7ct;T78C6!i^Hai&&#Ig?lT9L79h)FP81|`31|Y?I9h77rIum)gT|Ii zdl4P+g4^k{r$3?LYi4rG<^myA(lRa`3yUVReKx!NHb5y0H%yQuG$3LIMM?TlFq`Ip zUs!5I1@Vdt0dr@rn3FnWu;Mm{-P!)X!sxt3^dfrepgC~JOkdo7TjS{;A+OcSc=(&o z_8<83b>K_6p5)r!PHgH+ZDgUQtj@{%eO(VJy;Mr7P91*=-xlPOC}PEpzf z@d@#d$jLyetuApi8P(<6Nj4K=vt;jk5a}>U$8_w@4Hf&mEAw$T`enhNkj!^I#2MKf zl#ABWnXMhiTO(oH#IPjt>@~8_ea0s zCF%;MFvC@^5B0N2(^EmW zyPfbWT|2P0A;4~`^pZM*H49c-P)8ciuI z1vqT9&uW=T{NFgO+wM#4`|dF$KK{-~14muZgK7Vm4ALyD4yTiz$35?TXy5!FQa@ft zw#3TGR0*%^D%cj__2MK> zXr&=ksHQa!UtinT$H&JvKY#S)QpVDiL;;AL?agF2(@4L9$N9na}%4g}o z>Ktzl@&6UILy2J@$TxW`k8st$3)n^YA4xOw-j=Vx?k&o@@Hl|S5YJ;{&%25A@tdHG zPkmT~GL)WqH!>s`d$7W={mJblUFVnvK ziIz1QyNK-sEiuL$Kn&-#sx{&%GN?GmY}DldPdeML%zQQAjWJ~udvXfD3H&|r&YO!# z7kgXqA7y62qK>H0)`-h+)Ql&B=zZfvp&IL7jiaeNvlyi|AS)_rw(l{sE-#@*@1|?O z$9OA1$=}0#gq3xTvAF2ZuC^uOtMs8y*UzHF|24#`qPGkkgZXE{{YP`E(zBH+2mX$M zNuJ_VF>sv`qXDi|8)S23?~c((c8}zX zr1PHed6MA1Rm?*iP2*BN?tDy{mtnr)(nO3WL6UNi+Y$ zsQa@Y^^$B*u|CJfRqS8M|5Jps2=&FoAJt=I*7nS4^Woz->kc>@LUpEXR>fXVgKKqte5BvQ1bTj*tzR#sCpO{jqmv?JmRN%)iHoLppcd2aDeaiaUaDKKagO2&!1n zS9ghpG@nw$Ts0PEpELig_!I-@$mdu0G2*qV^!JEcu6&z4n{T#@k#*m!fWJ1N{q&of zerM}~HK|%ACcjJt$*(N-OlZHxG5cp(QO|@aD_UDB%9K|-@WJnh+(+F$6vvb0?(e9# zgWgcnYSxkaW%|X6$f$#v*U--xc4^5Pm|S~rzr@9`dV^lYhP9a6XO5H^{Wfayyz4{h f8rU-(?IG%>W98{2%aQE8&9nP>+8rI^ptXMiS5U)b diff --git a/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index f4af8c3b5d7de3c62a64766080b1fbd5f773ac02..a4941f120b83585f36bf1b7ce4ae2d35930d3214 100644 GIT binary patch literal 3881 zcmeHK+iu%N5Pc7je;CLFNCTqVegFZxQIZCTWhKhxK@f^1IW#vQm%?&sg>VAoGt%G7 zmvn~9tED0?`d}cb9>gVgXL#mt_RMTjsmRDe!E-eJ8ug8ga9Ql16e^L|l@>hr!e9=! zj~@a3c0!BXvtzzLflCpkQXwdjBNPdk6d{qA#b633bc`CpdN9~D9?+ona-m{j3S9?I zBC--sw?~()_?2w1Mzf?*;I4NV$)qNb3LEs#_W^#QAVf3+8>&;cOsLN z21vAeGY)<>hZ)5`n|#d)vpsWx%LYvFKo)1@N10bSs45RB`-oj4ng}jABQ=^zt6}*M z&8<{s>%5e?G{JAb{zDr6AmS9+EJ`u$Lx_9Wbn9F)HBXtD;QaRUojmy$qwm)GImvwA zKD;5HlXB4^T^43pW!aT}n(s{QP1dZ|Pc+7;j1<|Z^KeF8P(MG1afx{#z-ZNkKc+-C88}Unbx=16uH@sdW@(&net81$GsW9F1j_8G=6T zn%^{{;oFNF<#G6DBwg@rNNv1+Q;)%xW$-7v1DxrtKY}xYW|4fh7o^U)fqpD+hakY` z`aR8^zJ2-HVmfsC?aN>Dja8=2cH6yt zz}}%+t=EPHTgR8kZ8-R%45S)WY Q_7m9tw%g~AAJJC(8`vV?H~;_u literal 7756 zcmeHM+fExX5S`~reQ)0^h?F1^+I|2M6evaFRxa&BR8=7)kcuQIyA&eIueUwN6DRhr zHw`LP1&t8dwb%C8tyiBeS#@$Abt)Hm?9i?7$RX4|w- zcZPm_sgL??;jJkh^uLwo@(fS?yF?qd>qsT2ci-pHZU^5Ra*k2E7{lO~?fKS|7JgHF zV~KK`av`U-u4ljZQQ|y}oX8+5p(f)waAj;=!T5E^ImK@ZDSh-^mJ%e?F@AzJ3-b9M zqwS-guF^@M_EKm~SF$W+=<^bF4XmLBX{t%CcdYw&qxB_d|L`+7wkwNC-h=kO4(IYW zB&#+yq1zrLQOB#m5BGJFv;-~s78PgMjgsu4q`Upr?pJw)l(H;FcgshjkGOS=+7EQ^ zutqGX45IN2xT?rHS|-@1SC}=Q3sG4!obk*O>5mO(A1xx=LpEqy=1Z~fbEBP~1HKH( zy8m+%&So)Y^O&Qq9JU;Six5kWya8%EI5%Y3u6>?B9u}aUrdy zZ>fEY?5sACr?%C=dmz_eS^f->*u-fw7R@{{e4{1i*aod{teg~m2PjwId9?9q)r_On^LQ#)KL;X0jM5_@D=KO>MwnTa75Jcc!!uCCr~eM~ zeVnXoti?xvc-m%&pX3$By!mPT@5jdOzeBwG@s6PrF#j~T{{)U?WWrzd9QfM>CdtC; zG4PxbqXtiU8)S23@4EGooQ*gI=O&11F3^HJ9kM;SncUvQS2DEvC|L{Q_lcd=nOFVv zylO^u^a06JHsQ$cq9rUrCyh%QGP4XO4iPYu2#{0(g zj3j8c^4W)@p zp7SUbf*`uz2yTr{A`k$wHZ2UdmvUai%IC^@lxT->Xr- zmi=P>F6E8uvtB{iEBn>giT}s7ceAq+6nMC);g_BKKGvI+t^O9&c)x8I40ItchR5eQ{KJlwH()D%z{#@ zv2m5xiKybQzTV>q$=J3 z(d!Cw^Iya4RaSb)N#R@uBdz#W&A;EF-Ug7&`E+Dy=!@1dH)qfI z{NY3Vhg#KLsK^Tw>S&r-zBG$cvvYCxJT>^B%KW7niv za<@aZKU}{*<`(Q9v81!+-e+e%jTW*iIl!#PcJe!rvWm5wf?0goj3T&Wx;l3jrqM#l Y?&D-#`RJ$JaW@ELFqYl?*iO0X7w-bzu>b%7 diff --git a/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 b/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 index 910b89272f61adfba399d879bdc83f35e2be6b44..11d35ac57071184548116d949df98df23fab91e6 100644 GIT binary patch literal 4166 zcmeHK?QYvP6#ZYI?{H@ekOD~A_5cFn)m>MhalAO)ei%kUOH{={q70IXt7QfH813uz zNp`O&nNsW_0S2rK19P!Y6Nq3(7NzAoQPw5My4+$4BD+X5609jL6*sk# zZunQtt&nEpy%MD`@sB_JLmK|VbZ*$T;E+_(Fd-=m%dWC*HB)_Sz>vN9wLI*0PTKZOlFf?Zv}DgMi8vXhBlc%+F6NPtsb@5JU0 zDSpiEA9Q=T^$w;D4x635@P4hiY9NLM-w({SeHwLk5qjSU_Q}EFbT8a}t8TS)5y*S`$O=LL-39s_0lzk>-MyS`^XHs UBGQ5H>_*uWKwmXapI~+V4M5~MlK=n! literal 8326 zcmeHM+iuf95S?cv-r>!(k&;TJzz0O4+>vN0w7^4zP?|Il)FhSdQo`lefpd1U^{zb* zsQ{ruR5iBOd!0FZ_RRSEx1pTKMEa7;NT#?;W$0p&Vf( zmQCIJ)Qy|s{y=8t2wf@Wz*TSsE%e{RI0O8$rxa~F(!dBk^q-;5hP*yUZ@XxxtMnt# zQaLQ7E9poRwmU{yA8Qz5w7VE};?`T(`N7%xGSvV5GkD=vW{vz5)_d<}m;aHG)fx|B z+bKq(jkka?`gPGdGt@{OD&E2y4S9+uqAZm=&R`R z)A`Ch+7)#~g^osCz6HWsat}2#`0xhi&+CRc)(Ualy~O-QL)=S;O>!Brbm;glhu_!E zJii8fC3sfvB8e=XKcRj#t$%2YqMYJL~L#eVQ zOLNpt(Z=e1h1-jYTQXGcIP!@@#t2Uxxg|Hx$%c=BtqiQ3<9Yy==Be9vClyOLiswR} zpW&Gup3VOJCi3)@O`sXb`X}g-r6Cf@-HAgpcMR{i_tgKVzs-E$hrpAiFaZU!xWgc{`OnC;2UME4=ylIvBYluwYb zjkQ-->g1xTlX_Ln_>P)@s(LMmzP-w(W;nu|`dGNEvZ<{LB6JoQ>rN+nef<#s1rp zPe2-D2Wornz3Dt!@R=Jcx5e|O$ZpleGwMY~#;TS%6Y7f$f2R&50~h)Gc;?p-WZ9)_ z?DpjtU|BuGHT`_&*P-}#?ft6WuG{sNH$%&5WEYk+WW~cB(48Qr&k~7SY(aTsi z=PIFxuU>rCC}`8vT$@lWd-#v-tbS?9l_a*>GPAszT$fl!c9Gd;jxX*j9#cI~wh`yH zhgJD#ho|?pTa$Xm`>gwm>ks>U4Br!7I%}e#Jo9C&P+rM%%(^&NzW`5LSj)g^1p3H- z{|RT}cgHeTXgEJEwiWk7xF@&+IWPZBN#iIg8O;&-`Cf}!g}Hy8y?pjH*}F2}57?kM A3;+NC diff --git a/PoshServiceNow/Public/Get-ServiceNowTable.ps1 b/PoshServiceNow/Public/Get-ServiceNowTable.ps1 index 48667cc37d5efc4562647de426cbb95615a3b87a..b78eba08d3460256f50d4152a67329461fecf2d4 100644 GIT binary patch literal 3491 zcmds4QBNZ`5PnDEKa4`8UDWKRv~N^VODSAWIszr3RfP~WyA$HOU3+VL6VlWD_m1sN z?BpoDK2;(wY~r2q%r`UNe9T%=7%m08L6c2TEqH-rxty|x3itOu?(YG8ZZBKYv}U?$ zFugrdimmPr@BGmfQ>^xnssCdQ4q(h`1UUmUM=;hIEHP0Cf3~PrTs%UG`C|@T6ud-X z^kFc*ZLCi;s8Z+MK26YAkE3MLV8LgrQz-YUfQ)uLM3@`X91n*}{(_QdP92GQ0Js4UJ33#m#CM$)5cl?boDmY(Fo-1Xn_ znw!zl*E@jxHb!xBWSg@)^P0gwe9a;ElR?NA; z?&S4h_baP7F$~hkr#+)u>`w(1Y|v>0x#-vQB_qq|_^dWwkx;Q{TYa8UgJ$#w+|IYenvB0Kq= z{MFL7qop8;#O;0!D+Z+7F;GZh7#CfNO3;2A&H3%X4AOpZ1sTywUr-x% zGNIEYU9%Mg^;L%(j4aX%RAwqk&)6fs-XQXqZ{E&M^i@SgnBtRx>|CmXRF8FQKT&~0 zAJYY6TxMP;z+^@ASLcK!d&HUsH4i1vgx0aB-A`bo|q&uFOah$-x|~qa-(gLuL!L6U*lG*>bEkml`uNgxiaHjiR%X4`M8StI-W{bfg1%R1$KmpDtOGtfNs`^8Q+AP^?b1z? z#z=OcMty1Kik4^Z?5V)U62LLQ@3Muu)dorlk~+GR$1_<~a%pK`hwqQ!4*^FxoYHdX zIC2*XDC)AJ!J-$x$-%a@m5;QqKjR-_n@%yW`G;)2-LgSZHj)&Aqn=_js=cmpHj@lj zvS}-~kch;cboHR|HIOoK}wufU$*SCX0W}zc|JNAZ-(1u>KQ{vu>H-+@A zSjZ2UT~kY5kXDib5fbdxXW`TzX7C literal 6984 zcmeHMZEqVz5T4IS{D+fc$*E`@3g3bv2%&FMn}o&zp$G-nb{f<81)megp#F8>d1k!X zU3bn24V6HOEc@>Ec4ud2o_Y0Of1b*P45cGe>B|Urg*=rWo;KtV*NI$Wyo0+vyq!r) z+VWb?@%*WLB7f*_fi?Ub%RXpLWvss~nd7b}>lohwoe5UXtOK{mRc zJ%zbzShc5fd$=3PDSoGNhFy3KoE6}+Ck;^L_;28b=a}OhLwSRdbv!q5*Tg-?I{58k zYzP`9_)ED9J0IgLflo?@6xSv49>yrM={1kr;NnoFz&%dE!>-DBh*?qMPw=h>nRc;z zLmq;w0rnc=xeZz)<$YV~Sl`C15_6Yjcy}(3l&;6!KJ@+Tg5SnR*x4lZ6ek;DC!TOe z@pA@QRG+hiWG1S;H^5Up!R13&f1Xa)An6i1DHpmO$Vq~hBGI_vBx3DUwL&dTLBnv^ z#+_#|1!PBzjTB>D%!-KQ{_z|{Cbdh{o?)Dpv?ZJP%y81T_%`)@w8q1I#0u ziR3GcjX`59UxP{?Us~+8JkB^dk?*f<;{?1%PVTK>2uY%-#+CI3(TBt61Z zJ>(13H+{jjJd)25XQ)3f0(ZEc)rKoe+zd%sE(OeF-G<@ zGENcSYIvHc?rT6`Ey-#4TwsLQILGz&vH!aaU$(QMi}_c~nwVR8*zv~Jz{{?ByO0_7 zm9ql8Ge#4sW(94Gn4Qqlm@C_f!+Sp`C|pjCos9D1Wtofu?`N5(QQiB*yC!pBX4H7b16NH+MylCzlWR0Jp8+$p6ij zUxng-%l4nCR9WSOs=dnUJ#D6vvwA%pSzB~4sAb}0*@Fk|`F8#a-s=$cWYBI(nKeAC zw7Ofz7wDN-wo=E{ykXu=$onO^XX`9b&7MMvw*vVZV-b5ZmpIJ?GHc<<`ZHlwTD=t& z{53VY8lZbmC;VTUX1z_UD2#M9TMGRV1(wW#%nJb!E_*aMvzsHT+^D`wW; z%n$~sSq+zM*dm{;Bhy^;19B_pS^Vfxt)C`5K4W)o-{y&e9G9h^>u>ehLp-6r8i*xU z!Iz5~zJbxt@b$6Nbfeo5cnJyIIFF&TcDf?_^;uwQ)PCzN?hqI=lgGh8XrcrlFhl9COIc6d6&D zs#RWL`P{x%h`4%I8*aIH@>ZAG*=~>UI;=GI?EL+LFExp$7_7o%j#OVV%+n_DO{_d? z@YYwFk1^l03}6f6h5UpW7r3&=LG7>(We0kiuC66>A3)#9JRo-59xVME5-lm5g5BGk z_jqoLktw}Y68YZg8_JdcA6PydG{h&bOIJq(w1{FJ<0kJ|L#&Az+9uB1g6^!ZV;WC+ zNq1!wehvg(LW6I?%?4^M^O7%>H+GI#LvLJj6nWclt3rA>k6+KHk#3MW*Ts9%rgad1 m{0;w7S?6I4d=gJq!<#qR#J?YE>_wN=`cf diff --git a/PoshServiceNow/Public/Get-ServiceNowUser.ps1 b/PoshServiceNow/Public/Get-ServiceNowUser.ps1 index bf83b839273305b8dd3f6d022d6343d456e5f06c..d5065dd50ab1e6b0bfd92346c0d211ee439ab9db 100644 GIT binary patch literal 4106 zcmeHKZExE)5dL1E|KZ>WkOD~A_5%dOtGjMM<9KzteK3rHmQEE1y%;1FSIzq0cPC1w z6njX30V~kXUrb6o>h9s)a}TqoN{p;4c!MTdqq>&~F6+a4jq2g$3!vX#C{YG>%<~Jl z5lJp9gi4eMbp|F!$Rrjim>O!8qJmxP3^v^kXix>Es8V5S)y7^X3XPZBv&&ZeNj6xc zS<)!>*LzH4*1oE%3Oj#);_qqy*&9$m&iHosC++flV{+q7QSU@CZ%jTl(?-ea!`8dy zuzzf0pF#0M7nU1cz(OkPJ)_nEMYa$uP$%Ebb#m#}e$|-$CJISufCOtWfTknRUdCkbg*AJf`<>|jdUeyO};qQ;_f8aNdfhUgV zgw|)U|2;=)R74I6s@gCy=)68a-cVDb^cHDX5vkPsLbOBL(^iIFF{2CxVhiFMp_2(! z8`a<}oOPX>DO(i9dCFc`5XqRRBlg+uF=M|{m||t5D4@~A7<3$hnkzp_s5S81sS$t? z+(&T`97j*egpfMKQF+{vJCjZ`1i7ruvMGvN^}5`fHkhngt)0gs(c(EL-TRQ-bq-&^ z9qFU@@7_X2smEH$*#PI4s1hXhWD@S6`0~N_t=Gjc3X=kP6yN+)qYy|M)zlVPN;;th zb*Hq(eTG6*++9KvmRcXENrzpZc>*Bk%jS6OXA^4b0&-4nV1T-mr%bD==QYGs=h5zE%op6ir8O#z>>PlmE)Ae$$?Z&&_OWi@Sm9SobFx-fj? ioh{A3V4kLtwFdjgp`W_oojkIzTRA_}z{?j@Ykvc#BO_w~ literal 8214 zcmeHM+inv{5UppV{fAa!DUP%byB}bQEO!Y)AYu2xS|P_5FpA^IGa;BPzYd(!<@R*X z)C`UQtpZjQ&-7*bQg!;&r9Xcf%Y~fDKysPL3~x>z$_S;79N{^acc>rW?EtNp@=`Ki zdnLcgE%epDbLpdJU#8Md>O=cB`aMPaK;B@qGmPNy%l>?u$r!&m+E^N+$4E|P=<8;_ zeU1{>;^agY<_tY4*1*-XcN^pPG0zacIcAyT+pe@QLm%UFAG`AJHAXwcce=|k10|G0 zGP;wl>_BGcs2gApW6XBfOO*R9G?{D_%V8V@1c8D^r4 z_kk_ywQ05tJ?0)2uc3{WJVQyf{g>C*&I&0z^1G?67>P0B?qSq?OOrs3>wkI2cA4Mv{ba_D_)rTH!3%b~3L-)cCU^_Z<< zjuBnPM$x{&@n4llzn>714^|47Fr7=W(8+_Z;6?qi=9~Q*ld% z$~`ka@yM8<)RjNwk885wBVa277w34MfSYM+2i`uhhO-1Nq}7Zqb!?G?)h6=PwmNtS zGr6aKi?TNz~ zJ;15jaI|_J>hDy&k(1E6jA|j$Fyd|>}AupE|91*tJgsvJIwbrAN#KNl^OlfubKe2^f)dsvicZ$ zI{K*5^P{~6=tq=?(?eTZ&W$kkw9#EJPSl&&S=ZL}SGwsVL}U&s@b$5=mE zPqpaGc^vew{6(2D%cZ_&@PrFgY&6^RJYQsLEIruTRE;$2Z(lwDX^d^@+w<(rmeE4U zN?I8$+M6P$RTs~w78x04kLhe}K|uO`baL+bQJ~T_wxtFbWw?bAr_z zPWpw_-Z7&Ten+j8qZiIs)R%p{^s91fER$59%sDfvXqkCu&Z(LA7M{xLY5aVJuj_1B z%b(56e@7pZ@^88)IL5An2iXBP7o{DXx&{7UVJzC*IczuA7Hcfkbq9RToET$&$|f## zkOipo3fQ-)wNoRfI{C$t|Crbz-dAuhg$6ADz_MzVR#+FfsEJXnZ+9V~c%A7zO~{V_ zoZ4Jp=C)Mp^ka=1Y=k{hXpJ>tBPQ*y-pwaO)~*#?FwbB$H?R*=lhdpq(L>(9X( zGyIZ2=#e^q{@7CX`xrY1CgNQtZALsBIU*kWFd3QsnZ+UB-2u0zw^0t|k@r)Wxn$(Q zn!s?%Yuw9HTap7bsxXr%Xz`;W(b468`& z=&Gsf^2*ndLU|`Iu?8~&d5pF9Dfa=|y7e`uDc2U8kXd9@Mwv^Lo|OdBQ3 zyR~=2uzzo2pGomU2g_ZZ!AvTfJ+sylMX?afP$$1kb#m^;e%GA+C2~n+fJAFBVepd> zCWL=7TFnu&2j*g*1DIe(7FXmaS=0rTb+Mu9BX)^sB3N@pDm1k!-SF?4TUna5_f{6t z#J~OeA7%K5(3ugN93iPnBV@@{Sah4(Ze*@v4YXU~UgR}hS`smZqSl56n?k zlcQ$WueXr<8&|FedL-73>pmB=e_22ulie?RG*RD zLg2ZKAtL|ol~nCri|))m8+=cpu5&}#j}Hd7tw2Wh&)1Fq$ZPrWj?W4{L>63!JZdcn zSSJF}ND#mq-$sM9hACPA-|QdKX`#j7HjmqI4h=-?S;pn+-kx{s-hs6?LWy6A>eu)EQo{b1QpV=peKEr>fTsO?-h z0lQc%2XO(NINH3Ar}V>>mCDt6-GA8S+h?>`E=l84q0(#Q;|T**FSXPyc>n+a literal 8274 zcmeHMYfl?T6uqA-^*^k@l8qG8<_A~`Nhqz95E4lH!HO#52e`ryd6yFB@z>j&GuPvt z*}c0l3ROh05Vq&B^SJlSnRD;{`_D+OWh#BiWGplMO5{j}D7EDj-wXL0^?m$0M(d5d zmDJT9p=E|A=kig0lppYv{>`O_mYz(c71jIpUG#g2_P$(V+$qLN@X7xCHIorOGqkZZ zLXV+b$-vdkT>Angt}2mpS(-C+u_nI;?t{Hs7{7;k2KdY{%L31Kq=6ZF7@s@ZlXtfm z?W8mVZI!`Bx|5DHVZAx(`q;w=vpvJCQ@7vT(!Z?tm!kjOuRwie&HM`1`^&8^`%h+8 zYaGG0Gt5LA9{?-#Yu!Fm^jJ7lT)-O*d4-aC`>FF+bB&ayJTko%A~8hVbBwxJ?boAR zu|_QD97N*yWBK`(Z1^j%m4b^ie4m4xdDr&c{lps1;<=EwW_VMF zH?qIAi9Eeq6KDl;{k7xI7>Priw#1>CCx*Xx6LahYz2CceGCaFPxdoju#_ucqCgOE< z6a417bR_oReUjje9^+JPIa-y6>YcJ0xo;eO2}Hygr6M3JDryebnCZw9Xwc8AGhi{^ zE>QCQFi)L)gS~|4k5Ahc@pY=uQuCYW@BbU(RmXdVPQm<};QkMABqI}ks&e4x6qqCn zt770eBSsT^Q*DsVmA!jTBl$aG0M1Pj)m)(mc{*l$ax=Moh*omFYLwy)5sl7xMcbKUy99CR z8+n2927sTUJ-o&^3^{-Vv8?^5mQm2i%Vt!KNA=krXBXCZ?9moeDjj=7Y zJdE66suIWIMF>X!Kb6JzntUEtRRKJ~pq6XUic zFULM_gWH)OV;+Du3QKKd1gaDQ`_{F#E38#z#n1zvBaHIh1^1Qv!O{xW4QKg=b)J{% z*wuP=4;Bj78GANtc{pC)+!waBtNdn->+cbJB;OkP!A4S@7axk}%2o<%c7b$yK%-lI zk4PTpn?7*tPR_;zlAGVhOc^+ZuAGTQds#rL4RVZzzSB;nX6(a7x2ybl@j33xbu zf0dv-bjpUgPR1&%@r=l~6U>U#%@(s*Joj>Kh45|+-}}){WM9TI6WL#Bh8`H0WsQmU zO$D|O4ReZrGIef6wK{hh+hmhfa`&;S>>|(2j9)xfJg3^XXd|xe6ua`V5AX4pZcqC5 z#CxRsjr$MB{0%oKv7@V|uZt_+#0tfoyuqsTd-fCXae%!HoLZod{M(>#B_8{mSfSzk XSZ}Kkf7Imu%@S`>mi_wJPdV!gv4t;o diff --git a/PoshServiceNow/Public/New-ServiceNowIncident.ps1 b/PoshServiceNow/Public/New-ServiceNowIncident.ps1 index a0f02f5d27c4c25f36030b1778c66bd5e0d86f30..db4d60cf42282706bbeb07b833a39fe540ad42d5 100644 GIT binary patch literal 4600 zcmds5QBT`25PnDEKb%CR6s_e4OhOv!7(-$Ot*{q_keggukHoHQhpLR%YB}@^O>fW81iEkRDT-M;o| zf@Vzbj-$x}W1g-?QV4X0f8v-WIvPOEM8b?ztK*(g1s>jQsgca_+AgQxN$o4Nk)daq zoU-hsF!LAmX!2jo?s_AK-N4)HpAKL$m&!nbI#zt)PO3t@#@Gu7!2K;4y9lpC@S_Ki zfcBUjz=agE*WjD7Om81;PXYX@aNT-wGddf~>R@~tsAj@5t@%vkR3l)fWU+9m-jV5N zZgRVH52AL*P(4|rBn zi|1-_SLNJ#@fM+2!O{kc8Jtm>-@I$^Xm$kA7|l|uhp78T*$lA~vmHXM!lwn>q?pEU zjNGooSpZE7v}VbRrAYa#P|RJ!++g00!A?XrL#|Wozf8~okaNPL1z%ifBXdX{MFXZ` z&h*@{X@=c3YWI*@J4`Ikfl<=c7EU9DmTYsD0rBO;l4C~n(Y~@dYsa3NH!9USX#R*Q zfALiLx=oe8v5XUsrY69Qi!8fTr}@IH`i;7NHSrb)G`r`G^z#EcY9H?ha81p^&DRS^ zB{c!`?AOqprwtP^!W4-Ymr(R^_I^Dfs0BEp?!h)GLm`((vCP9V|8LN!n3H!hz=1q% z0dVr8Pzcl=$h@p0zWD&@x(}c_V;C0|2FiLpfCUjQy4R8c(BZv=ptt4rIZV1P@BwT@ zN0_YJgvaMP%fs04ZkEQ;xw(gO)FZtGYB+`uRm*9w<*4i`sm+XNrs|WtZ;`gW(S6Vx zIk7h14;HjV1F{=Pd1`y_sIAl5VsL>t1)*hcy0ozzgwxfnTe(n@mtbD|i@7x4j{~VV zPp0=Vul8t_-BRvX`BQ%LwBM*WRhk6g){wum$Og5kI_;J=Aa(1W8-@a*C#XDZsBQj@ zaBXY-sW8OWhVB`nx^0bMSeCUFOa+ z#;P=kUb444yF2st&FqYSez#>LJ!wfI9l6A(NVX-GE2+yKo&))T_7*;E0OKIb8B4>~pVXmfh@x!_E z?>f2JBg`{`B<;J2XHu~4gWFyS=8GVkeFs=Uj2&`b&fh_=<;;%!st=`qyEl&Hj7t*s z>)WWa1iGRQVp)|MwAja|7G$@v>vgB&o@?xL(&>}ox9!dzd3^TVc3%X~eg#$8b@nrtacA*td1jmjQDq*!35Fbk z8Bf8z^pcDtB77SFg(I+L@ahpx4$qGri+G>DnHo7u?{0JL9IFXDZ!vnNkCTd-vUs*U zR@V${1$>mVAmg8l6e1N%>Z`jzCVhJZ+%iV?(JDQBOU@liEq1j%M-^oG$kRWoORwga z?iZC7TVPsyzjRj2qUA1RF_MqLaT?86x!1(fK>r4?R&zJ91h+4aK6j_DIvVC!tI5m9 zS{6U$Xxjr<9lLw)zX=Z(NyM6kaN zcN`mDfZHDTUObQ0o^!0G`6de?TVs5bqpt;AG5%xJ7CEHF$PO`!76EPid*+^J=+guv zGN%}snVspQv^k6U_*9>^CaW>{G%Pl0Va??QWTdmJ<#<{LOT{kA=Z&-j%yfYlN@6Qx zerArFXwm3jdof>4X7=yN&-tu5bz>uCQZtX2RsM{XPG*(&vD)&i@>iz`=IV8)tOPK} zJ%WC^vV-v(IDyP|ULz-7d{fv(F5J?woy}e}>krm=X3VKwOT!Czw+|kmeGcRcGF@Z} z#?j#pXIqT-JhBUQ#`;GD28n?R=8My)SVHTmyhU4nL=R(`-)J}l1x(Z-gSC_fHnR74%aS%8)TZSKSd*W?D$jN_t{qV8>3BpvQMM|>*d)|GSeIfvLp;#VSsV<| zqPFHr`uNNYm)_S-Tt!Du-a|2H>E+O2B^QVz^nc$495tv@b8>4a=Ho z&FOgyE#XsyI*_iHjK~OL6~FItRZj2mYVMBZYn58ftc}NH>q+Su!sy{`-RQ`9oyodU zkakyo-=4v)Mg^&MX4jTwWo?hZd_HR%q?YI4Z0X8`J{!zBsOp}2OlReaMyqG?`IYqO z>>GRh5d1KCV-8a6yOAxc1#UTkv?HLSliP=VAM(*|THZ~@o2B2dj=bdRm3EAi^(NW+ zyvJT1C$scTzi_H380joEv(S`Vzq%6GW;(esgo7xC2S;qKLLV?@z^BkY3{G_K!( zMApZzA-xWd@7tL@BUjTFJPqtcyVi5(Jggo_nTP6}fl&+lOnG7F-|* zRw2k7Oo5PdEHf|?q{>jip&c7OcN5T{iYg{DW~6H4AZMk<#ePzzjpE{NAKcgp>oyMM zJqpaeG80~mW#gL<30LR{5Q^?%8URs(I(@m)>0+$?Qw$$j$q6Cu&_te{<6VG9qrCG- zPaxvZHk`xyhUvnvLy3?|VHg({YSk<0)U$eOAc^3}%9>sknp%+rP}SN{u}KTS?<_TC z3sJ+%5)O7;b)aoz&~Q`0YMcB8?P37853cPk8+!?fJ__i=KM_!}(T+vW{{P~?auREY zzZb-Zongv!c73oGC-3G?HP+iU8w}+dgDwdWLm0ktCp?dwKTlhSOMHNkED|m#GBzOg z={uLydUKm>Zr7he_va&$?SEUCY<5>e@e>%!*c-Cp4Xg2CU2_{eieTpq=MwS`7ZgT& z+)*9TkNchC&80%}VidgYa?AxxjPT+cwt8Cql%e;{{~ZDuab8+< z3M^vm|L6K2L@ZuJ3J^1-M&|U0nsixw^y+%CQE{icQr?1Vea;H)G3@$ng$fa`2X}&@ zvKsbm123Yirc~Qzq@U$pH@tCDT-g0iMH=M0yJft-`*$33ZyogrAK4>^e0K1OIfPl> z(6>|j`+Jn{9u7*L!#L&4lIYyJHxip!xJx*7h>7&T-FWU6EHoq35~n*-3EgMAPz`lM!ZUoQ-HN?e<@^7Q)kBL$vtbj7pj?8ObC8$en)CwdOMSZBg`WhAycxvFM& m#bev=L!c6~poMpMgSYI6ZG_6P{}iY2h86FM-=M0lL-`gD@{`E` diff --git a/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 b/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 index 9fc1c11f632c71c9b9501539fdb2df2869bcba25..2b569347a3800af15a7080cf037b1fe2e050f182 100644 GIT binary patch literal 2853 zcmds3QE%He5PmPv|8TGcSivkA?Op;8en#(LqEDsoh0Ar+cq)s9QlCtY<{Z0J^ z#enXQ?I_VA?Rsn81}qN=Bl5_*@4ox))(uZ}AvoONHd>rxM3B7ScA?Hv@wD$jwC|C6-r(3M_OqCA;ym}Ez=@HuGN{l;;uF~ zqedB4jAu*>xtj%AHh6Y_@>J`IIln}0UZ0JYHKxUScO^K-Hkj)I%S?@)e8EbgGk*K< zj&6CnF}d-o6c4PtXmoyPrnDpk?t>Q1v5Us7hVVU8c?TS!xM5|33J9=9Auw7ItP)cp zvyp;YirRpR%3W|8zBMb={{X*ykIjAXQ;W<$V0b0b(5hgi!7VfRF-nH{lrl}k6yT^0 z;Gx%(DePBYrPUbTIHD%UL?uTHVlfqwzG=$xt(;f2-h~HTTr8c(9?1jeq}v~pyUyVu zB*ci-?T@e)vSo*}F*T1s7;2`}mda!dl$);sgr)1$o@_mS(lKsBo{nWcKJLgCt z_jw<_LJg^-xCzk9`t5v~n1DOGVhv&7E`x|81e}OyCD+Qi5pT*vN?o%wUvjU90J2GJ;WI=nQ39E|<7u(6^#mI%z ztv=X9BWY_3v$OVs>;Z?!B9rzt zJNwtSy-;Qlbe(PL9(UVb6FLf#>>k^W=-C;T_9XR@w4i#t)VUN}7|h?NSQ`nL0{ko* zs2Zgq6CjAucHmfxvJ_h*1V@TLgu9xOaD*Bq{`=KFYyihp|{`&a&&(EI*<1ZH0mqxG8 zFL#=Tjv3t9nlvRH&v_~`Grdfwt7Ls1lL)ov!q$DFPWM;h z#OYW&n6$Ibq#KDWKAjWDuEaf`)!Y_RB&L3nIrt{|WDF)M6aC w=pw>WlgcE!8ezcdx-_E!v1{^7s;1P>pHWr)4cCo;@c;k- literal 5690 zcmeHL+iu%N5S`}&{RhGlAO*E#w0#L&L0W{XNN29QbS2@nzz8PNG_K%vomMT%Bu>*Gg)AK zfV-D?yOf^v<*nS}`6=e+c)yb0Ql@L0hnPp% zZP?VuS1Eoend^KcP2A7muOTG8xreOMCtf~%o5QEN_D5LVIjk7M(<69cB`451#vey~ zWKQvJ2;ZkzN$Vq6aN+!FX?}&6|6JJeF*K_;zQx)m(A3BEF}zG9Y}1yxXb=zAh(6Ch@|W~-5tlOPWm?{tm7 zevuiJPQ^seRM2Hy3GigqEdAnely#UuC-x6`vw|i40*~_LabjgB?wc$oBX>mS2H1?LD+AOo1BA;Q`R(2^bsN=1n3Wh9Ju?mqxbl#{m0w3$%ZC z=GUS4|H}Q%8ef<7R{s-vPJ2j>grf~q57rPy+G24ZK|9x9gTci|7uhbFGdh;f%2cjvxVYCa4KWRvkj%q8e`J+2p!&JLyrJnEjne{~*Y9ratD>pFbJ zvODPRGK}9sD>I=74ey-qI&$hzPreI%5L;cXZWbr&3j9tc>|YajdIkNgnRnPHC^q}( zA^EITwOjO`ai()Eb_J=APZv3xL28`i+r1yhZ~NLkBQRbq*Td#ukW7x{2!Ab%e&MiT z$HqeA1#BG^-?bp44|yY8$B4`l*M)ouxmI+-vG3wxj6J8G znjB+1ksmQ*j_VzM8Jz?@D^Df3mnTQZCmiep*}+n(?+CPquj}!tIorqS^zgp0Bs)A^WD_n~C!W zZSz@fRn>ziLo{E)c!&2*c><{^m|rVHyiZHycZ@4X#`W%d#E~oe#_0+rHY)S|{_6s{ zc`6T`?K5De?{sQhGvH$C*2jvPK(;^gVH_D3?kQ&&=exOkuAVe-7c_={cw#{;{w06P zAGjXY+=n(dAu~rm@etlv;ZDyrm|2&Vs_1KS*PZh*x@m#YH>fSgsA@eYr(5(rr95^j z-q&TXRC&?HT0ua$qxDl+V1C^VXkI=2l${CfBNY6^ES)bb31EK zl54HlQ48_OSn{`rxDr!D1}pazxbkNN%2Y=<$x}=pU>4VuVg3`$&fHAh{qvsZY7daD OTm{j13;B$WX4=1UnS9v* diff --git a/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 b/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 index 413d744bb7fd79813ac274e949f6ca200aa98ff6..bce206b1964c283767fccc82d995dd0570508455 100644 GIT binary patch literal 465 zcmb`DF$=;l5QX=G|KSD)JLE@{QbdprP1R9iywX6Ml;Nq?K*^I;|{6;kr6pcLUqZm8%KXPD>7OB r)i5PIqGh9+{zDu#iL?d^^CVzOq*}w-R;Ql znN6vhDcApHI7E*^3wDhTruvF`Fundt%kESRsSwbANsYr4C#{oxgi!^?{()1^oCbRO Vu}AI6ERSzEH=FGq_f7PH^EZmjj1&L> diff --git a/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 b/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 index a212ce57ffececd9c370eb199447577510a72e3f..723ac3c40fa013a186f1c31bfa492122b25d9e8d 100644 GIT binary patch literal 2622 zcmeHJ-%r~x5PlvK|HG+7YS5ZSY;Qi~KHUYn9*5tskO2r^rEfSYpPsHU@GH8s5>V1DjP`gdm5_=>uofgo3p$ZFo&xx@T^0oq-9*v>i?8^ z$~-N9q3l3oPNL#WKxHrotAG*r?pDSuy8l7d0DK16{VfWE84vrhKie+aq@^lk>Pod$_)jRJZONfuRg(8X|IeB16&%*WQK5u zPB)&4e-F0Ne8A9xNkG={?ftCC6=-r)!MrPlIRxbgu{|0DQA-;69+b?OnbLU=s5h?> z6l!@<0MEI=GtF;P{Fd&YGBdHxTHCD;Fze#BUDw}jouGv*sM}#{HT>#mIC5C)5I%-D z3V9%r2$3WWQZ6SiGI96gKGcGYc)n~%g8@+76tx{G@_+Ye=$#5$`TEP%$)33sWKJV| zw2&Mto#9IA#rY9LOdFizEUBFo$o(u9eVQV6j|EL>KlHobo{beeeQHP3?6vY6d=0S0 z?rum1(4AOYn%y+*!uu68fyQgi=~*{rB~PWArPG~mfKy*RH9baQ(9;~ETOgN&L*g2> zs`FRc@lw@cGl%KfQlIKN>-yq&gvPcGa(57&88Wu*XQi;%y9H$cQGJH(hRwrc6ZlyJ zNpbi7>}$n2l`civX0jo*rAs@}Y6hL7#|%q1{ks5PRRu+5EaVClDY|)w7%L&v%pZ@d zX1@#HCG7O!fCrfN literal 5246 zcmeI0TW=#p5QXa%B>qDyu@tXZI|AM!?ZcA2MPe^nJ4h&6fr*`sA+aNSl57_3UkAR^ z<<895?F$J!AgwIVrDwXTy6V)an*Qt06T7sL9a~{T8*>%xtqts)>nqMJ>u{WKJ>;E% zy<+^@y4JH_?Tq`U%qVz%V}ICJ_N5)!K6Cr=Sz+HZYs8(7@2$x*X*l72!dnOYFOVeN zk8H3l5Px$ZCEK7Ji%A@?U6nZ#-vh zV>IJ7Uv`_&C5n53_O3#eN&?lvoe=U-&JsL2_O8XOu1G#*gmSTYT}({ zX3VqiK3wz=3tnRBB42jb^5u`w6XJAVsp^lI@e&p|v)9aj8mmY_b~jh>?i=zy=i_>v zNh~S0SoCCWzSbu1<~+R3v+k?{9a2?);Qj>rC!AAd%IOJ_S;SxRnW}Dp_Xf9oQ=;N? zWRJ)YRo%q%xj5vb=@D5SzsL3wq5i-x+DQ@`;e+zGQV22dfsuuNl0XAzaL01bzh!Yx|od?~n#9rQs zr@M6aEI6LwSv_YJX@M>?p;>+Zgq3wcq4)o3R;Q9{(x3BJJJyi8>=qr{l<_mPDpR{? z_z->9vS$(NV!5gh>Q>L!v>X%r3SJ@S8mp^4X_)nXs+8x}o*}YFzps0*rR`ZyS&l^N7e?bH1`~keiE6b?g%os`vU9ksnGl=XB>Ixrp#UOjAa!;&Z)s_w1O**`~hE ztt`z|G&b|kqLLyTG%)PqK$Mg8jrBmz>Wz zDmsB$txjFviQ?$`K7_hI^{vXQ^6PO`XD=-2sjz=rEOAO9BCDyw@(_0GpF|89jIv2P!~8ApG}e<{mzRduU|BF~p1k|f;~vF?p(^BXX=GoK@ST^4V_h3d(@hu9?-%C9}$r5%PR;H7F+Rln-S0c*Zu z#lK@$EAF-lIWMD?r;MxHYu(z`h?a|=TXXL`VTSKs327~`Ax-mrNS-b8@3z>nll~jz zH7eJV?K>Y{ExWv-{U~LIs>KC%Xn#=OXr3Lr>V3BwbFx#cu|p7PvT+QMqQ}gvW<#}UtRrWmZiJ6iXKYH zzsbwYo0rMw$DN+E&{RR0a#lMU%d^|JxzIEADV7UPUvvaI=s|DV))v^ZEtRUEKdRHP zSLZicBcg8)x&t~T-i$HeyU?qKa;yttcy)FAgRhlgGVb1kai9y$wbzQSv)l}uF}x!q zPd+`JTTUs=;@-nCU@cY4E#pe(o-R@N815boN@T|Ex#iSmUo|r9Hg-;@+{`sG4};dX zyVgi&yx5SQ@P>i5g!@2!T7q?#Ug=p^?l0a)Iw9(n>QUUUJYuwj$SEu`=7m*QpNc!c g{@?iRij~?_~{j5z1U&H_|EdT%j From a03e8a55912edb26e1affd86193843b1e0c78bde Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 24 Mar 2017 17:19:58 -0500 Subject: [PATCH 025/348] Overhaul 2017.03.24 --- .gitignore | 2 +- MAKE.ps1 | 24 ++- PSServiceNow-ConfigurationManagement.psm1 | 82 -------- PSServiceNow-Users.psm1 | 188 ------------------ .../PoshServiceNow-Automation.json | Bin 1600 -> 1604 bytes .../PoshServiceNow.format.ps1xml | 4 +- .../PoshServiceNow.psd1 | 21 +- PoshServiceNow/PoshServiceNow.psm1 | 22 ++ .../Public/Get-ServiceNowChangeRequest.ps1 | Bin 0 -> 7524 bytes .../Get-ServiceNowConfigurationItem.ps1 | Bin 0 -> 7756 bytes .../Public/Get-ServiceNowIncident.ps1 | Bin 0 -> 8326 bytes PoshServiceNow/Public/Get-ServiceNowTable.ps1 | Bin 0 -> 6984 bytes PoshServiceNow/Public/Get-ServiceNowUser.ps1 | Bin 0 -> 8214 bytes .../Public/Get-ServiceNowUserGroup.ps1 | Bin 0 -> 8274 bytes .../Public/New-ServiceNowIncident.ps1 | Bin 0 -> 9202 bytes PoshServiceNow/Public/New-ServiceNowQuery.ps1 | Bin 0 -> 2752 bytes .../Public/New-ServiceNowTableEntry.ps1 | Bin 0 -> 5690 bytes .../Public/Remove-ServiceNowAuth.ps1 | Bin 0 -> 480 bytes .../Public/Remove-ServiceNowTableEntry.ps1 | Bin 0 -> 5246 bytes PoshServiceNow/Public/Set-ServiceNowAuth.ps1 | Bin 0 -> 814 bytes .../Public/Test-ServiceNowAuthIsSet.ps1 | Bin 0 -> 298 bytes Readme.md | 14 +- .../PoshServiceNow.Tests.ps1 | 25 ++- Tests/Test.ps1 | 25 +++ build.ps1 | 30 +++ psake.ps1 | 134 +++++++++++++ 26 files changed, 259 insertions(+), 312 deletions(-) delete mode 100644 PSServiceNow-ConfigurationManagement.psm1 delete mode 100644 PSServiceNow-Users.psm1 rename PSServiceNow-Automation.json => PoshServiceNow/PoshServiceNow-Automation.json (94%) rename PSServiceNow.format.ps1xml => PoshServiceNow/PoshServiceNow.format.ps1xml (95%) rename PSServiceNow.psd1 => PoshServiceNow/PoshServiceNow.psd1 (84%) create mode 100644 PoshServiceNow/PoshServiceNow.psm1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowIncident.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowTable.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowUser.ps1 create mode 100644 PoshServiceNow/Public/Get-ServiceNowUserGroup.ps1 create mode 100644 PoshServiceNow/Public/New-ServiceNowIncident.ps1 create mode 100644 PoshServiceNow/Public/New-ServiceNowQuery.ps1 create mode 100644 PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 create mode 100644 PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 create mode 100644 PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 create mode 100644 PoshServiceNow/Public/Set-ServiceNowAuth.ps1 create mode 100644 PoshServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 rename PSServiceNow.Tests.ps1 => Tests/PoshServiceNow.Tests.ps1 (86%) create mode 100644 Tests/Test.ps1 create mode 100644 build.ps1 create mode 100644 psake.ps1 diff --git a/.gitignore b/.gitignore index 0778a37..6316a65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ ServiceNow-Module.Pester.Defaults.json *.zip -PSServiceNow.Pester.Defaults.json +PoshServiceNow.Pester.Defaults.json diff --git a/MAKE.ps1 b/MAKE.ps1 index 7f70d6c..b45cc77 100644 --- a/MAKE.ps1 +++ b/MAKE.ps1 @@ -13,17 +13,17 @@ function New-MakePackage{ [string]$PackageName, [string]$ModuleName ) - @($FilePatternExclusions | %{"MAKE.zip" -match $_}).contains($true) + @($FilePatternExclusions | ForEach-Object{"MAKE.zip" -match $_}).contains($true) - $FilesToInclude = Get-ChildItem -Path $here | ?{ + $FilesToInclude = Get-ChildItem -Path $here -Recurse | Where-Object { $File=$_; !$_.PSIsContainer -and - !($PackageFilePatternExclusions | %{$File.Name -match $_}).contains($true) + !($PackageFilePatternExclusions | ForEach-Object{$File.Name -match $_}).contains($true) } # Create temporary folder and copy the files we want into it New-Item $here\$ModuleName -ItemType Container -Force | Out-Null - $FilesToInclude | %{Copy-Item -Path $_.FullName -Destination $here\$ModuleName\$_ -Force} + $FilesToInclude | ForEach-Object {Copy-Item -Path $_.FullName -Destination $here\$ModuleName\$_ -Force} # Create a zip based on that folder (overwriting it if it already exists) $ZipFile = "$here\$PackageName" @@ -38,7 +38,7 @@ Function Update-CodeCoveragePercent{ [string]$TextFilePath="$here\Readme.md" ) $ReadmeContent = Get-Content $TextFilePath - $ReadmeContent = $ReadmeContent | %{$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} + $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} Set-Content -Path $TextFilePath -Value $ReadmeContent } @@ -50,7 +50,7 @@ Function UpdateManifest{ Write-Verbose "Updating $ManifestPath to version $Version" $ManifestContent = Get-Content $ManifestPath - $ManifestContent = $ManifestContent | %{$_ -replace "ModuleVersion = '(\d|\.)+'", "ModuleVersion = '$Version'"} + $ManifestContent = $ManifestContent | ForEach-Object{$_ -replace "ModuleVersion = '(\d|\.)+'", "ModuleVersion = '$Version'"} Set-Content -path $ManifestPath -Value $ManifestContent } @@ -65,19 +65,21 @@ $PackageFilePatternExclusions = @( ) $here = Split-Path -Parent $MyInvocation.MyCommand.Path +$Here = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell' -$Version = "0.1.13" -$ModuleName = "PSServiceNow" -$PackageName = "$ModuleName-v$($version).zip"; +$Version = "0.1.12" +$ModuleName = "PoshServiceNow" +$PackageName = "$ModuleName-v$($version).zip" # Perform Pester tests -$TestResult = Invoke-Pester -CodeCoverage '*.psm1' -PassThru +$CodeCoverage = Join-Path $Here (Join-Path $ModuleName "$($ModuleName).psm1") +$TestResult = Invoke-Pester -Path $Here -CodeCoverage $CodeCoverage -PassThru $CoveragePercent = 100-(($testResult.CodeCoverage.NumberOfCommandsMissed/$testResult.CodeCoverage.NumberOfCommandsAnalyzed)*100) # Update/Create the package and if($TestResult.FailedCount -eq 0){ New-MakePackage -PackageFilePatternExclusions $PackageFilePatternExclusions -PackageName $PackageName -ModuleName $ModuleName Update-CodeCoveragePercent -CodeCoverage $CoveragePercent - UpdateManifest -ManifestPath "$here\$ModuleName.psd1" -Version $Version + UpdateManifest -ManifestPath "$here\$ModuleName\$ModuleName.psd1" -Version $Version } \ No newline at end of file diff --git a/PSServiceNow-ConfigurationManagement.psm1 b/PSServiceNow-ConfigurationManagement.psm1 deleted file mode 100644 index 427c5c1..0000000 --- a/PSServiceNow-ConfigurationManagement.psm1 +++ /dev/null @@ -1,82 +0,0 @@ -function Get-ServiceNowConfigurationItem { - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, - - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - - # Set the default property set for the table view - $DefaultProperties = @('name', 'category', 'subcategory') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(‘DefaultDisplayPropertySet’,[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} \ No newline at end of file diff --git a/PSServiceNow-Users.psm1 b/PSServiceNow-Users.psm1 deleted file mode 100644 index 934afcc..0000000 --- a/PSServiceNow-Users.psm1 +++ /dev/null @@ -1,188 +0,0 @@ - -<# -.EXAMPLE - Get-ServiceNowUserGroup -MatchContains @{'name'='Architect'} -#> - -function Get-ServiceNowUserGroup{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # Set the default property set for the table view - $DefaultProperties = @('name', 'email', 'sys_id') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} - -<# -.EXAMPLE - Get-ServiceNowUser -MatchExact @{'name'='Sam Martin'} -#> -function Get-ServiceNowUser{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # Set the default property set for the table view - $DefaultProperties = @('name', 'email', 'sys_id') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} \ No newline at end of file diff --git a/PSServiceNow-Automation.json b/PoshServiceNow/PoshServiceNow-Automation.json similarity index 94% rename from PSServiceNow-Automation.json rename to PoshServiceNow/PoshServiceNow-Automation.json index 04fdc456cd762c1356cf741e53f72b4f88481343..7d5081887974aeb8bb77e0a4432220699a15f784 100644 GIT binary patch delta 17 YcmX@WbA)Gu92;vsLoq|fWO+7405EF=nE(I) delta 13 UcmX@YbAV@q92;ZsWMwu*03R9yq5uE@ diff --git a/PSServiceNow.format.ps1xml b/PoshServiceNow/PoshServiceNow.format.ps1xml similarity index 95% rename from PSServiceNow.format.ps1xml rename to PoshServiceNow/PoshServiceNow.format.ps1xml index 667c8c9..7fe4a02 100644 --- a/PSServiceNow.format.ps1xml +++ b/PoshServiceNow/PoshServiceNow.format.ps1xml @@ -2,9 +2,9 @@ - PSServiceNow.ChangeRequest + PoshServiceNow.ChangeRequest - PSServiceNow.ChangeRequest + PoshServiceNow.ChangeRequest diff --git a/PSServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 similarity index 84% rename from PSServiceNow.psd1 rename to PoshServiceNow/PoshServiceNow.psd1 index af7de64..b23c6da 100644 --- a/PSServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -1,5 +1,5 @@ # -# Module manifest for module 'PSServiceNow' +# Module manifest for module 'PoshServiceNow' # # Generated by: Sam Martin # @@ -9,10 +9,10 @@ @{ # Script module or binary module file associated with this manifest. -RootModule = 'PSServiceNow.psm1' +RootModule = 'PoshServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.14' +ModuleVersion = '0.1.18.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -60,19 +60,13 @@ Description = 'This module provides cmdlets allowing you to retrieve information # TypesToProcess = @() # Format files (.ps1xml) to be loaded when importing this module -FormatsToProcess = @('PSServiceNow.format.ps1xml') +FormatsToProcess = @('PoshServiceNow.format.ps1xml') # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @( - 'PSServiceNow-Tables.psm1', - 'PSServiceNow-Incidents.psm1', - 'PSServiceNow-Users.psm1', - 'PSServiceNow-ConfigurationManagement.psm1', - 'PSServiceNow-Changes.psm1' -) +NestedModules = @() # Functions to export from this module -FunctionsToExport = '*' +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet') # List of all modules packaged with this module # ModuleList = @() @@ -104,5 +98,4 @@ PrivateData = @{ # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' -} - +} \ No newline at end of file diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/PoshServiceNow/PoshServiceNow.psm1 new file mode 100644 index 0000000..9cb7a74 --- /dev/null +++ b/PoshServiceNow/PoshServiceNow.psm1 @@ -0,0 +1,22 @@ +#Requires -Version 3.0 +[cmdletbinding()] +param() + +Write-Verbose $PSScriptRoot + +Write-Verbose 'Import everything in sub folders folder' +foreach($Folder in @('Private', 'Public')) +{ + $Root = Join-Path -Path $PSScriptRoot -ChildPath $Folder + if(Test-Path -Path $Root) + { + Write-Verbose "processing folder $Root" + $Files = Get-ChildItem -Path $Root -Filter *.ps1 -Recurse + + # dot source each file + $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | + ForEach-Object {Write-Verbose $_.basename; . $_.FullName} + } +} + +Export-ModuleMember -Function (Get-ChildItem -Path "$PSScriptRoot\Public\*.ps1").BaseName \ No newline at end of file diff --git a/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..67616e60f656e4ffd4ba48bfef85cf288bd9cbb8 GIT binary patch literal 7524 zcmeHMU2oGc6ur+#{D-J3YA4YFuSk;^+Zae=8)Jiq2~Ay_j-q~yB>Sjfe;qi-w_cpY z39U4Q3e~hGajviJ>*M3&o1Z^=aw#L}NFse1<1UaL3GvjD_qaxKh4K#W_VD&vHs!Ol zVRep@L;Qb5?NDOa2l7oG$^%^W?*eua{)f`cl-u_!uzQR59eC`+V~FRGvFF`bdiYK7 zj!!*Ugfft>DI1&j5uVt;K+a_1ZQ(@HK5#^|ZlXWze;2GN)DlFCBM;%bfjC~^u7ff3(AuVnGRK?7{MFs~V%Xn*501^qd@b)IdS9k} z`4cT`G8Uz+)9z#C)AD0bx(eiQh6?436k zlP>nQ;6KXDf<+xsp{)^@=RjCfwqO}!#-5=6ysmoNS|ZM3e$f#3!C^Ixl2rRC@?VvhV^v1JilhFG%Y4NyD83L2s>BXd0iGRcC-=`1i8;}(hHQRTXS(g`3qqoyF z;A6ZMpycmiKElen##mhRXII-2@m2cJr|V}?;{O`rRnc39j=}u1;QpgIRq5GEl>>iA zz$8y`su;M=h|vI7stvNavUl5PB)dm+!MQQC_y88<=`7omo5}4V-jbnJqvUrGw~lYE zF4f7Rs*`e6&GQ{K0abO)IelA|P0cXCoAR@8US(5Tr%2S6RdrBf+xDt7_K6fZr0FRu z?xgdc@OhHpzE#Xa98Kd=KJI)>nU`U{;nGBmC*^Id*9(+Qpqk449N>(z32Uk_o}`)o zVbuNEk9tWqs92w4<0|&A)i;|_8?LIYJndZA2@Y~8@rPz}! zI?@xmFOu%t7EZ5ayP2cTZ*4jh+wJnC#8?+o7W@7%Hc~EBUsdjxRTmw6%qd7#qbSyl5 TWI2$%vw3tM54*kRIJNdK+kw4S literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..f4af8c3b5d7de3c62a64766080b1fbd5f773ac02 GIT binary patch literal 7756 zcmeHM+fExX5S`~reQ)0^h?F1^+I|2M6evaFRxa&BR8=7)kcuQIyA&eIueUwN6DRhr zHw`LP1&t8dwb%C8tyiBeS#@$Abt)Hm?9i?7$RX4|w- zcZPm_sgL??;jJkh^uLwo@(fS?yF?qd>qsT2ci-pHZU^5Ra*k2E7{lO~?fKS|7JgHF zV~KK`av`U-u4ljZQQ|y}oX8+5p(f)waAj;=!T5E^ImK@ZDSh-^mJ%e?F@AzJ3-b9M zqwS-guF^@M_EKm~SF$W+=<^bF4XmLBX{t%CcdYw&qxB_d|L`+7wkwNC-h=kO4(IYW zB&#+yq1zrLQOB#m5BGJFv;-~s78PgMjgsu4q`Upr?pJw)l(H;FcgshjkGOS=+7EQ^ zutqGX45IN2xT?rHS|-@1SC}=Q3sG4!obk*O>5mO(A1xx=LpEqy=1Z~fbEBP~1HKH( zy8m+%&So)Y^O&Qq9JU;Six5kWya8%EI5%Y3u6>?B9u}aUrdy zZ>fEY?5sACr?%C=dmz_eS^f->*u-fw7R@{{e4{1i*aod{teg~m2PjwId9?9q)r_On^LQ#)KL;X0jM5_@D=KO>MwnTa75Jcc!!uCCr~eM~ zeVnXoti?xvc-m%&pX3$By!mPT@5jdOzeBwG@s6PrF#j~T{{)U?WWrzd9QfM>CdtC; zG4PxbqXtiU8)S23@4EGooQ*gI=O&11F3^HJ9kM;SncUvQS2DEvC|L{Q_lcd=nOFVv zylO^u^a06JHsQ$cq9rUrCyh%QGP4XO4iPYu2#{0(g zj3j8c^4W)@p zp7SUbf*`uz2yTr{A`k$wHZ2UdmvUai%IC^@lxT->Xr- zmi=P>F6E8uvtB{iEBn>giT}s7ceAq+6nMC);g_BKKGvI+t^O9&c)x8I40ItchR5eQ{KJlwH()D%z{#@ zv2m5xiKybQzTV>q$=J3 z(d!Cw^Iya4RaSb)N#R@uBdz#W&A;EF-Ug7&`E+Dy=!@1dH)qfI z{NY3Vhg#KLsK^Tw>S&r-zBG$cvvYCxJT>^B%KW7niv za<@aZKU}{*<`(Q9v81!+-e+e%jTW*iIl!#PcJe!rvWm5wf?0goj3T&Wx;l3jrqM#l Y?&D-#`RJ$JaW@ELFqYl?*iO0X7w-bzu>b%7 literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 b/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..910b89272f61adfba399d879bdc83f35e2be6b44 GIT binary patch literal 8326 zcmeHM+iuf95S?cv-r>!(k&;TJzz0O4+>vN0w7^4zP?|Il)FhSdQo`lefpd1U^{zb* zsQ{ruR5iBOd!0FZ_RRSEx1pTKMEa7;NT#?;W$0p&Vf( zmQCIJ)Qy|s{y=8t2wf@Wz*TSsE%e{RI0O8$rxa~F(!dBk^q-;5hP*yUZ@XxxtMnt# zQaLQ7E9poRwmU{yA8Qz5w7VE};?`T(`N7%xGSvV5GkD=vW{vz5)_d<}m;aHG)fx|B z+bKq(jkka?`gPGdGt@{OD&E2y4S9+uqAZm=&R`R z)A`Ch+7)#~g^osCz6HWsat}2#`0xhi&+CRc)(Ualy~O-QL)=S;O>!Brbm;glhu_!E zJii8fC3sfvB8e=XKcRj#t$%2YqMYJL~L#eVQ zOLNpt(Z=e1h1-jYTQXGcIP!@@#t2Uxxg|Hx$%c=BtqiQ3<9Yy==Be9vClyOLiswR} zpW&Gup3VOJCi3)@O`sXb`X}g-r6Cf@-HAgpcMR{i_tgKVzs-E$hrpAiFaZU!xWgc{`OnC;2UME4=ylIvBYluwYb zjkQ-->g1xTlX_Ln_>P)@s(LMmzP-w(W;nu|`dGNEvZ<{LB6JoQ>rN+nef<#s1rp zPe2-D2Wornz3Dt!@R=Jcx5e|O$ZpleGwMY~#;TS%6Y7f$f2R&50~h)Gc;?p-WZ9)_ z?DpjtU|BuGHT`_&*P-}#?ft6WuG{sNH$%&5WEYk+WW~cB(48Qr&k~7SY(aTsi z=PIFxuU>rCC}`8vT$@lWd-#v-tbS?9l_a*>GPAszT$fl!c9Gd;jxX*j9#cI~wh`yH zhgJD#ho|?pTa$Xm`>gwm>ks>U4Br!7I%}e#Jo9C&P+rM%%(^&NzW`5LSj)g^1p3H- z{|RT}cgHeTXgEJEwiWk7xF@&+IWPZBN#iIg8O;&-`Cf}!g}Hy8y?pjH*}F2}57?kM A3;+NC literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Get-ServiceNowTable.ps1 b/PoshServiceNow/Public/Get-ServiceNowTable.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..48667cc37d5efc4562647de426cbb95615a3b87a GIT binary patch literal 6984 zcmeHMZEqVz5T4IS{D+fc$*E`@3g3bv2%&FMn}o&zp$G-nb{f<81)megp#F8>d1k!X zU3bn24V6HOEc@>Ec4ud2o_Y0Of1b*P45cGe>B|Urg*=rWo;KtV*NI$Wyo0+vyq!r) z+VWb?@%*WLB7f*_fi?Ub%RXpLWvss~nd7b}>lohwoe5UXtOK{mRc zJ%zbzShc5fd$=3PDSoGNhFy3KoE6}+Ck;^L_;28b=a}OhLwSRdbv!q5*Tg-?I{58k zYzP`9_)ED9J0IgLflo?@6xSv49>yrM={1kr;NnoFz&%dE!>-DBh*?qMPw=h>nRc;z zLmq;w0rnc=xeZz)<$YV~Sl`C15_6Yjcy}(3l&;6!KJ@+Tg5SnR*x4lZ6ek;DC!TOe z@pA@QRG+hiWG1S;H^5Up!R13&f1Xa)An6i1DHpmO$Vq~hBGI_vBx3DUwL&dTLBnv^ z#+_#|1!PBzjTB>D%!-KQ{_z|{Cbdh{o?)Dpv?ZJP%y81T_%`)@w8q1I#0u ziR3GcjX`59UxP{?Us~+8JkB^dk?*f<;{?1%PVTK>2uY%-#+CI3(TBt61Z zJ>(13H+{jjJd)25XQ)3f0(ZEc)rKoe+zd%sE(OeF-G<@ zGENcSYIvHc?rT6`Ey-#4TwsLQILGz&vH!aaU$(QMi}_c~nwVR8*zv~Jz{{?ByO0_7 zm9ql8Ge#4sW(94Gn4Qqlm@C_f!+Sp`C|pjCos9D1Wtofu?`N5(QQiB*yC!pBX4H7b16NH+MylCzlWR0Jp8+$p6ij zUxng-%l4nCR9WSOs=dnUJ#D6vvwA%pSzB~4sAb}0*@Fk|`F8#a-s=$cWYBI(nKeAC zw7Ofz7wDN-wo=E{ykXu=$onO^XX`9b&7MMvw*vVZV-b5ZmpIJ?GHc<<`ZHlwTD=t& z{53VY8lZbmC;VTUX1z_UD2#M9TMGRV1(wW#%nJb!E_*aMvzsHT+^D`wW; z%n$~sSq+zM*dm{;Bhy^;19B_pS^Vfxt)C`5K4W)o-{y&e9G9h^>u>ehLp-6r8i*xU z!Iz5~zJbxt@b$6Nbfeo5cnJyIIFF&TcDf?_^;uwQ)PCzN?hqI=lgGh8XrcrlFhl9COIc6d6&D zs#RWL`P{x%h`4%I8*aIH@>ZAG*=~>UI;=GI?EL+LFExp$7_7o%j#OVV%+n_DO{_d? z@YYwFk1^l03}6f6h5UpW7r3&=LG7>(We0kiuC66>A3)#9JRo-59xVME5-lm5g5BGk z_jqoLktw}Y68YZg8_JdcA6PydG{h&bOIJq(w1{FJ<0kJ|L#&Az+9uB1g6^!ZV;WC+ zNq1!wehvg(LW6I?%?4^M^O7%>H+GI#LvLJj6nWclt3rA>k6+KHk#3MW*Ts9%rgad1 m{0;w7S?6I4d=gJq!<#qR#J?YE>_wN=`cf literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Get-ServiceNowUser.ps1 b/PoshServiceNow/Public/Get-ServiceNowUser.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..bf83b839273305b8dd3f6d022d6343d456e5f06c GIT binary patch literal 8214 zcmeHM+inv{5UppV{fAa!DUP%byB}bQEO!Y)AYu2xS|P_5FpA^IGa;BPzYd(!<@R*X z)C`UQtpZjQ&-7*bQg!;&r9Xcf%Y~fDKysPL3~x>z$_S;79N{^acc>rW?EtNp@=`Ki zdnLcgE%epDbLpdJU#8Md>O=cB`aMPaK;B@qGmPNy%l>?u$r!&m+E^N+$4E|P=<8;_ zeU1{>;^agY<_tY4*1*-XcN^pPG0zacIcAyT+pe@QLm%UFAG`AJHAXwcce=|k10|G0 zGP;wl>_BGcs2gApW6XBfOO*R9G?{D_%V8V@1c8D^r4 z_kk_ywQ05tJ?0)2uc3{WJVQyf{g>C*&I&0z^1G?67>P0B?qSq?OOrs3>wkI2cA4Mv{ba_D_)rTH!3%b~3L-)cCU^_Z<< zjuBnPM$x{&@n4llzn>714^|47Fr7=W(8+_Z;6?qi=9~Q*ld% z$~`ka@yM8<)RjNwk885wBVa277w34MfSYM+2i`uhhO-1Nq}7Zqb!?G?)h6=PwmNtS zGr6aKi?TNz~ zJ;15jaI|_J>hDy&k(1E6jA|j$Fyd|>}AupE|91*tJgsvJIwbrAN#KNl^OlfubKe2^f)dsvicZ$ zI{K*5^P{~6=tq=?(?eTZ&W$kkw9#EJPSl&&S=ZL}SGwsVL}U&s@b$5=mE zPqpaGc^vew{6(2D%cZ_&@PrFgY&6^RJYQsLEIruTRE;$2Z(lwDX^d^@+w<(rmeE4U zN?I8$+M6P$RTs~w78x04kLhe}K|uO`baL+bQJ~T_wxtFbWw?bAr_z zPWpw_-Z7&Ten+j8qZiIs)R%p{^s91fER$59%sDfvXqkCu&Z(LA7M{xLY5aVJuj_1B z%b(56e@7pZ@^88)IL5An2iXBP7o{DXx&{7UVJzC*IczuA7Hcfkbq9RToET$&$|f## zkOipo3fQ-)wNoRfI{C$t|Crbz-dAuhg$6ADz_MzVR#+FfsEJXnZ+9V~c%A7zO~{V_ zoZ4Jp=C)Mp^ka=1Y=k{hXpJ>tBPQ*y-pwaO)~*#?FwbB$H?R*=lhdpq(L>(9X( zGyIZ2=#e^q{@7CX`xrY1CgNQtZALsBIU*kWFd3QsnZ+UB-2u0zw^0t|k@r)Wxn$(Q zn!s?%Yuw9HTap7bsxXr%Xz`;W(b468`& z=&Gsf^2*ndLU|`Iuj&GuPvt z*}c0l3ROh05Vq&B^SJlSnRD;{`_D+OWh#BiWGplMO5{j}D7EDj-wXL0^?m$0M(d5d zmDJT9p=E|A=kig0lppYv{>`O_mYz(c71jIpUG#g2_P$(V+$qLN@X7xCHIorOGqkZZ zLXV+b$-vdkT>Angt}2mpS(-C+u_nI;?t{Hs7{7;k2KdY{%L31Kq=6ZF7@s@ZlXtfm z?W8mVZI!`Bx|5DHVZAx(`q;w=vpvJCQ@7vT(!Z?tm!kjOuRwie&HM`1`^&8^`%h+8 zYaGG0Gt5LA9{?-#Yu!Fm^jJ7lT)-O*d4-aC`>FF+bB&ayJTko%A~8hVbBwxJ?boAR zu|_QD97N*yWBK`(Z1^j%m4b^ie4m4xdDr&c{lps1;<=EwW_VMF zH?qIAi9Eeq6KDl;{k7xI7>Priw#1>CCx*Xx6LahYz2CceGCaFPxdoju#_ucqCgOE< z6a417bR_oReUjje9^+JPIa-y6>YcJ0xo;eO2}Hygr6M3JDryebnCZw9Xwc8AGhi{^ zE>QCQFi)L)gS~|4k5Ahc@pY=uQuCYW@BbU(RmXdVPQm<};QkMABqI}ks&e4x6qqCn zt770eBSsT^Q*DsVmA!jTBl$aG0M1Pj)m)(mc{*l$ax=Moh*omFYLwy)5sl7xMcbKUy99CR z8+n2927sTUJ-o&^3^{-Vv8?^5mQm2i%Vt!KNA=krXBXCZ?9moeDjj=7Y zJdE66suIWIMF>X!Kb6JzntUEtRRKJ~pq6XUic zFULM_gWH)OV;+Du3QKKd1gaDQ`_{F#E38#z#n1zvBaHIh1^1Qv!O{xW4QKg=b)J{% z*wuP=4;Bj78GANtc{pC)+!waBtNdn->+cbJB;OkP!A4S@7axk}%2o<%c7b$yK%-lI zk4PTpn?7*tPR_;zlAGVhOc^+ZuAGTQds#rL4RVZzzSB;nX6(a7x2ybl@j33xbu zf0dv-bjpUgPR1&%@r=l~6U>U#%@(s*Joj>Kh45|+-}}){WM9TI6WL#Bh8`H0WsQmU zO$D|O4ReZrGIef6wK{hh+hmhfa`&;S>>|(2j9)xfJg3^XXd|xe6ua`V5AX4pZcqC5 z#CxRsjr$MB{0%oKv7@V|uZt_+#0tfoyuqsTd-fCXae%!HoLZod{M(>#B_8{mSfSzk XSZ}Kkf7Imu%@S`>mi_wJPdV!gv4t;o literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/New-ServiceNowIncident.ps1 b/PoshServiceNow/Public/New-ServiceNowIncident.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a0f02f5d27c4c25f36030b1778c66bd5e0d86f30 GIT binary patch literal 9202 zcmeHNVM`l95S`D3{)YpFC^h*31)*ZC6CUFOa+ z#;P=kUb444yF2st&FqYSez#>LJ!wfI9l6A(NVX-GE2+yKo&))T_7*;E0OKIb8B4>~pVXmfh@x!_E z?>f2JBg`{`B<;J2XHu~4gWFyS=8GVkeFs=Uj2&`b&fh_=<;;%!st=`qyEl&Hj7t*s z>)WWa1iGRQVp)|MwAja|7G$@v>vgB&o@?xL(&>}ox9!dzd3^TVc3%X~eg#$8b@nrtacA*td1jmjQDq*!35Fbk z8Bf8z^pcDtB77SFg(I+L@ahpx4$qGri+G>DnHo7u?{0JL9IFXDZ!vnNkCTd-vUs*U zR@V${1$>mVAmg8l6e1N%>Z`jzCVhJZ+%iV?(JDQBOU@liEq1j%M-^oG$kRWoORwga z?iZC7TVPsyzjRj2qUA1RF_MqLaT?86x!1(fK>r4?R&zJ91h+4aK6j_DIvVC!tI5m9 zS{6U$Xxjr<9lLw)zX=Z(NyM6kaN zcN`mDfZHDTUObQ0o^!0G`6de?TVs5bqpt;AG5%xJ7CEHF$PO`!76EPid*+^J=+guv zGN%}snVspQv^k6U_*9>^CaW>{G%Pl0Va??QWTdmJ<#<{LOT{kA=Z&-j%yfYlN@6Qx zerArFXwm3jdof>4X7=yN&-tu5bz>uCQZtX2RsM{XPG*(&vD)&i@>iz`=IV8)tOPK} zJ%WC^vV-v(IDyP|ULz-7d{fv(F5J?woy}e}>krm=X3VKwOT!Czw+|kmeGcRcGF@Z} z#?j#pXIqT-JhBUQ#`;GD28n?R=8My)SVHTmyhU4nL=R(`-)J}l1x(Z-gSC_fHnR74%aS%8)TZSKSd*W?D$jN_t{qV8>3BpvQMM|>*d)|GSeIfvLp;#VSsV<| zqPFHr`uNNYm)_S-Tt!Du-a|2H>E+O2B^QVz^nc$495tv@b8>4a=Ho z&FOgyE#XsyI*_iHjK~OL6~FItRZj2mYVMBZYn58ftc}NH>q+Su!sy{`-RQ`9oyodU zkakyo-=4v)Mg^&MX4jTwWo?hZd_HR%q?YI4Z0X8`J{!zBsOp}2OlReaMyqG?`IYqO z>>GRh5d1KCV-8a6yOAxc1#UTkv?HLSliP=VAM(*|THZ~@o2B2dj=bdRm3EAi^(NW+ zyvJT1C$scTzi_H380joEv(S`Vzq%6GW;(esgo7xC2S;qKLLV?@z^BkY3{G_K!( zMApZzA-xWd@7tL@BUjTFJPqtcyVi5(JgRunZw1A>T3J~lR(ChhLl7^JVRJ!htq%w%_k z+M-D5?(EE+d+(fk=G^@HImIOw7^A=pOO6csNU_3W4EWCQjq_uU`dnS%4Xri1#t%Hi z1N(2dM}OxSa%G4!w4-^y-k{BEu8(m_p9}gie9B&@-exXehC*0vO=vf~v zdOK$fon(T~)_)6+D!o-@+hG1jJZHxJA^r{tW$L223=B_lM9ZAEPjO)1oyu7Ei^4me zYtAekeyL?e!CaC}HVMyc`0a8^@F$3tap;4_b+`EZ-g15XM$9(qio;ieB zUeWiQd`R!$QN9N_EO`#&lru}BbE{({HnVV->eORRqy?_ix$d{si%>_L=13vb$EvCt z`u5mY-QGHUr}QgLbDF5iJ!5XZ4=b{%(Ss-WO1m|YuJir78YcJ@#p)8Pz1m1&R^f?# zgsU9}$R@NC>IcL-L_F5@mHmaHzF^qfD?Qc(^>#BSWK2?&P literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 b/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..9fc1c11f632c71c9b9501539fdb2df2869bcba25 GIT binary patch literal 5690 zcmeHL+iu%N5S`}&{RhGlAO*E#w0#L&L0W{XNN29QbS2@nzz8PNG_K%vomMT%Bu>*Gg)AK zfV-D?yOf^v<*nS}`6=e+c)yb0Ql@L0hnPp% zZP?VuS1Eoend^KcP2A7muOTG8xreOMCtf~%o5QEN_D5LVIjk7M(<69cB`451#vey~ zWKQvJ2;ZkzN$Vq6aN+!FX?}&6|6JJeF*K_;zQx)m(A3BEF}zG9Y}1yxXb=zAh(6Ch@|W~-5tlOPWm?{tm7 zevuiJPQ^seRM2Hy3GigqEdAnely#UuC-x6`vw|i40*~_LabjgB?wc$oBX>mS2H1?LD+AOo1BA;Q`R(2^bsN=1n3Wh9Ju?mqxbl#{m0w3$%ZC z=GUS4|H}Q%8ef<7R{s-vPJ2j>grf~q57rPy+G24ZK|9x9gTci|7uhbFGdh;f%2cjvxVYCa4KWRvkj%q8e`J+2p!&JLyrJnEjne{~*Y9ratD>pFbJ zvODPRGK}9sD>I=74ey-qI&$hzPreI%5L;cXZWbr&3j9tc>|YajdIkNgnRnPHC^q}( zA^EITwOjO`ai()Eb_J=APZv3xL28`i+r1yhZ~NLkBQRbq*Td#ukW7x{2!Ab%e&MiT z$HqeA1#BG^-?bp44|yY8$B4`l*M)ouxmI+-vG3wxj6J8G znjB+1ksmQ*j_VzM8Jz?@D^Df3mnTQZCmiep*}+n(?+CPquj}!tIorqS^zgp0Bs)A^WD_n~C!W zZSz@fRn>ziLo{E)c!&2*c><{^m|rVHyiZHycZ@4X#`W%d#E~oe#_0+rHY)S|{_6s{ zc`6T`?K5De?{sQhGvH$C*2jvPK(;^gVH_D3?kQ&&=exOkuAVe-7c_={cw#{;{w06P zAGjXY+=n(dAu~rm@etlv;ZDyrm|2&Vs_1KS*PZh*x@m#YH>fSgsA@eYr(5(rr95^j z-q&TXRC&?HT0ua$qxDl+V1C^VXkI=2l${CfBNY6^ES)bb31EK zl54HlQ48_OSn{`rxDr!D1}pazxbkNN%2Y=<$x}=pU>4VuVg3`$&fHAh{qvsZY7daD OTm{j13;B$WX4=1UnS9v* literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 b/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..fa820378b54f208a442374f0b8a6dbf365658d67 GIT binary patch literal 480 zcmchUF$)4Q429n;_#bX?^%ppah>P5Cr|zd#Jn*hks}AB{SHEUaL~s!)O0L{rydjJ3c literal 0 HcmV?d00001 diff --git a/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 b/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..a212ce57ffececd9c370eb199447577510a72e3f GIT binary patch literal 5246 zcmeI0TW=#p5QXa%B>qDyu@tXZI|AM!?ZcA2MPe^nJ4h&6fr*`sA+aNSl57_3UkAR^ z<<895?F$J!AgwIVrDwXTy6V)an*Qt06T7sL9a~{T8*>%xtqts)>nqMJ>u{WKJ>;E% zy<+^@y4JH_?Tq`U%qVz%V}ICJ_N5)!K6Cr=Sz+HZYs8(7@2$x*X*l72!dnOYFOVeN zk8H3l5Px$ZCEK7Ji%A@?U6nZ#-vh zV>IJ7Uv`_&C5n53_O3#eN&?lvoe=U-&JsL2_O8XOu1G#*gmSTYT}({ zX3VqiK3wz=3tnRBB42jb^5u`w6XJAVsp^lI@e&p|v)9aj8mmY_b~jh>?i=zy=i_>v zNh~S0SoCCWzSbu1<~+R3v+k?{9a2?);Qj>rC!AAd%IOJ_S;SxRnW}Dp_Xf9oQ=;N? zWRJ)YRo%q%xj5vb=@D5SzsL3wq5i-x+DQ@`;e+zGQV22dfsuuNl0XAzaL01bzh!Yx|od?~n#9rQs zr@M6aEI6LwSv_YJX@M>?p;>+Zgq3wcq4)o3R;Q9{(x3BJJJyi8>=qr{l<_mPDpR{? z_z->9vS$(NV!5gh>Q>L!v>X%r3SJ@S8mp^4X_)nXs+8x}o*}YFzps0*rR`ZyS&l^N7e?bH1`~keiE6b?g%os`vU9ksnGl=XB>Ixrp#UOjAa!;&Z)s_w1O**`~hE ztt`z|G&b|kqLLyTG%)PqK$Mg8jrBmz>Wz zDmsB$txjFviQ?$`K7_hI^{vXQ^6PO`XD=-2sjz=rEOAO9BCDyw@(_0GpF|89jIv2P!~8ApG}e<{mzRduU|BF~p1k|f;~vF?p(^BXX=GoK@ST^4V_h3d(@hu9?-%C9}$r5%PR;H7F+Rln-S0c*Zu z#lK@$EAF-lIWMD?r;MxHYu(z`h?a|=TXXL`VTSKs327~`Ax-mrNS-b8@3z>nll~jz zH7eJV?K>Y{ExWv-{U~LIs>KC%Xn#=OXr3Lr>V3BwbFx#cu|p7PvT+QMqQ}gvW<#}UtRrWmZiJ6iXKYH zzsbwYo0rMw$DN+E&{RR0a#lMU%d^|JxzIEADV7UPUvvaI=s|DV))v^ZEtRUEKdRHP zSLZicBcg8)x&t~T-i$HeyU?qKa;yttcy)FAgRhlgGVb1kai9y$wbzQSv)l}uF}x!q zPd+`JTTUs=;@-nCU@cY4E#pe(o-R@N815boN@T|Ex#iSmUo|r9Hg-;@+{`sG4};dX zyVgi&yx5SQ@P>i5g!@2!T7q?#Ug=p^?l0a)Iw9(n>QUUUJYuwj$SEu`=7m*QpNc!c g{@?iRij~?_~{j5z1U&H_|EdT%j literal 0 HcmV?d00001 diff --git a/Readme.md b/Readme.md index 8ae7a55..ffe331b 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,5 @@ -# 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-68%25-yellowgreen.svg) +# PoshServiceNow +[![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) 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. @@ -8,19 +8,19 @@ Requires PowerShell 3.0 or above as this is when `Invoke-RestMethod` was introdu ## Usage Download the [latest release](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: -`Import-Module PSServiceNow` -Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module PSServiceNow`. +`Import-Module PoshServiceNow` +Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module PoshServiceNow`. ### Example - Retrieving an Incident Containing the Word 'PowerShell' ``` -Import-Module PSServiceNow +Import-Module PoshServiceNow Set-ServiceNowAuth Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} ``` ### Example - Retrieving an Incident Containing the Word 'PowerShell' While Passing Authentication ``` -Import-Module PSServiceNow +Import-Module PoshServiceNow Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} -ServiceNowCredential $PSCredential -ServiceNowURL $ServiceNowURL ``` @@ -31,7 +31,7 @@ Update-ServiceNowIncident -SysID $Incident.Sys_ID -Values @{comments='Updated vi ``` ### 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). +The module can use the `Connection` parameter in conjunction with the included `PoshServiceNow-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). The `Connection` parameter accepts a hashtable object that requires a username, password, and ServiceNowURL. diff --git a/PSServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 similarity index 86% rename from PSServiceNow.Tests.ps1 rename to Tests/PoshServiceNow.Tests.ps1 index 0db3b06..b2f49f4 100644 --- a/PSServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -1,10 +1,21 @@ -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$DefaultsFile = "$here\PSServiceNow.Pester.Defaults.json" +<# +$moduleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path +$ModuleName = "PoshServiceNow" +#> -# Load defaults from file (merging into $global:ServiceNowPesterTestDefaults +$projectRoot = Resolve-Path "$PSScriptRoot\.." +$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") +$moduleName = Split-Path $moduleRoot -Leaf +$DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +# Load defaults from file (merging into $global:ServiceNowPesterTestDefaults) if(Test-Path $DefaultsFile){ $defaults = if($global:ServiceNowPesterTestDefaults){$global:ServiceNowPesterTestDefaults}else{@{}}; - (Get-Content $DefaultsFile | Out-String | ConvertFrom-Json).psobject.properties | %{$defaults."$($_.Name)" = $_.Value} + (Get-Content $DefaultsFile | Out-String | ConvertFrom-Json).psobject.properties | ForEach-Object { + $defaults."$($_.Name)" = $_.Value + } + + $defaults.Creds = (Get-MDSCredentials User) # Prompt for credentials $defaults.Creds = if($defaults.Creds){$defaults.Creds}else{Get-Credential} @@ -20,12 +31,12 @@ if(Test-Path $DefaultsFile){ TestUserGroup = 'e9e9a2406f4c35001855fa0dba3ee4f3' TestUser = "7a4b573a6f3725001855fa0dba3ee485" } | ConvertTo-Json | Set-Content $DefaultsFile - return; + return } # Load the module (unload it first in case we've made changes since loading it previously) -Remove-Module PSServiceNow -ErrorAction SilentlyContinue -Import-Module $here\PSServiceNow.psd1 +Remove-Module $ModuleName -ErrorAction SilentlyContinue +Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -Force Describe "ServiceNow-Module" { diff --git a/Tests/Test.ps1 b/Tests/Test.ps1 new file mode 100644 index 0000000..203aa2b --- /dev/null +++ b/Tests/Test.ps1 @@ -0,0 +1,25 @@ +<# +$DomainSuffix = 'iheartmedia.com' + +$UserName = '1113192' +$newFolderName = "$UserName".ToUpper() +$newFolderFull = "\\CIHM01SATRA\c$\users\1113193\desktop\$newFolderName" + +[system.io.directory]::CreateDirectory($newFolderFull) + +$AddAccessRule = New-Object 'security.accesscontrol.filesystemaccessrule'("$UserName@$($DomainSuffix)",@("FullControl"),"ContainerInherit,Objectinherit","None","Allow") +$acl = Get-Acl $newFolderFull +$acl.AddAccessRule($AddAccessRule) +set-acl -aclobject $acl $newFolderFull +#> + +$projectRoot = Resolve-Path "$PSScriptRoot\.." +$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") +$moduleName = Split-Path $moduleRoot -Leaf +$DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +Write-Host "ProjectRoot: " $projectroot +Write-Host "moduleroot: " $moduleroot +Write-Host "modulename: " $modulename +Write-Host "DefaultsFile: " $DefaultsFile +Test-Path $DefaultsFile \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..60bc41c --- /dev/null +++ b/build.ps1 @@ -0,0 +1,30 @@ +<# +.Description +Installs and loads all the required modules for the build. +.Author +Warren F. (RamblingCookieMonster) +#> + +[cmdletbinding()] +param ($Task = 'Default') + +# Grab nuget bits, install modules, set build variables, start build. +Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null + +$Modules = @("Psake", "PSDeploy","BuildHelpers","PSScriptAnalyzer", "Pester") + +ForEach ($Module in $Modules) { + If (-not (Get-Module -Name $Module -ListAvailable)) { + Switch ($Module) { + Pester {Install-Module $Module -Force -SkipPublisherCheck} + Default {Install-Module $Module -Force} + } + + } + Import-Module $Module +} + +Set-BuildEnvironment + +Invoke-psake -buildFile .\psake.ps1 -taskList $Task -nologo +exit ( [int]( -not $psake.build_success ) ) \ No newline at end of file diff --git a/psake.ps1 b/psake.ps1 new file mode 100644 index 0000000..ef2a930 --- /dev/null +++ b/psake.ps1 @@ -0,0 +1,134 @@ +# PSake makes variables declared here available in other scriptblocks +# Init some things +Properties { + # Find the build folder based on build system + $ProjectRoot = $ENV:BHProjectPath + if(-not $ProjectRoot) + { + $ProjectRoot = $PSScriptRoot + } + + $Timestamp = Get-date -uformat "%Y%m%d-%H%M%S" + $PSVersion = $PSVersionTable.PSVersion.Major + $TestFile = "TestResults_PS$PSVersion`_$TimeStamp.xml" + $lines = '----------------------------------------------------------------------' + + $Verbose = @{} + if($ENV:BHCommitMessage -match "!verbose") + { + $Verbose = @{Verbose = $True} + } +} + +Task Default -Depends Deploy + +Task Init { + $lines + Set-Location $ProjectRoot + "Build System Details:" + Get-Item ENV:BH* | Format-List + "`n" +} + +<# +Task Analyze -Depends Init { + $saResults = Invoke-ScriptAnalyzer -Path $script -Severity @('Error', 'Warning') -Recurse -Verbose:$false + if ($saResults) { + $saResults | Format-Table + Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' + } +} +#> + +Task UnitTests -Depends Init { + $lines + 'Running quick unit tests to fail early if there is an error' + $TestResults = Invoke-Pester -Path $ProjectRoot\Tests\*unit* -PassThru -Tag Build + + if($TestResults.FailedCount -gt 0) + { + Write-Error "Failed '$($TestResults.FailedCount)' tests, build failed" + } + "`n" +} + +Task Test -Depends UnitTests { + $lines + "`n`tSTATUS: Testing with PowerShell $PSVersion" + + # Gather test results. Store them in a variable and file + $CodeCoverage = Join-Path $Env:BHPSModulePath "$($Env:BHProjectName).psm1" + $TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile "$ProjectRoot\$TestFile" -Tag Build + #$CoveragePercent = 100-(($testResult.CodeCoverage.NumberOfCommandsMissed/$testResult.CodeCoverage.NumberOfCommandsAnalyzed)*100) + + # In Appveyor? Upload our tests! #Abstract this into a function? + If($ENV:BHBuildSystem -eq 'AppVeyor') + { + [xml]$content = Get-Content "$ProjectRoot\$TestFile" + $content.'test-results'.'test-suite'.type = "Powershell" + $content.Save("$ProjectRoot\$TestFile") + + "Uploading $ProjectRoot\$TestFile to AppVeyor" + "JobID: $env:APPVEYOR_JOB_ID" + (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path "$ProjectRoot\$TestFile")) + } + + #Remove-Item "$ProjectRoot\$TestFile" -Force -ErrorAction SilentlyContinue + + # Failed tests? + # Need to tell psake or it will proceed to the deployment. Danger! + if($TestResults.FailedCount -gt 0) + { + Write-Error "Failed '$($TestResults.FailedCount)' tests, build failed" + } + "`n" +} + +Task Build -Depends Test { + $lines + + $functions = Get-ChildItem "$PSScriptRoot\$env:BHProjectName\Public\*.ps1" | + Where-Object{ $_.name -notmatch 'Tests'} | + Select-Object -ExpandProperty basename + + # Load the module, read the exported functions, update the psd1 FunctionsToExport + Set-ModuleFunctions -Name $env:BHPSModuleManifest -FunctionsToExport $functions + + # Bump the module version + $version = [version] (Step-Version (Get-Metadata -Path $env:BHPSModuleManifest)) + $galleryVersion = Get-NextPSGalleryVersion -Name $env:BHProjectName + if($version -lt $galleryVersion) + { + $version = $galleryVersion + } + $version = [version]::New($version.Major,$version.Minor,$version.Build,$env:BHBuildNumber) + Write-Host "Using version: $version" + + Update-Metadata -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -Value $version +} + +Task Deploy -Depends Build { + $lines + + # Gate deployment + if( + $ENV:BHBuildSystem -ne 'Unknown' -and + $ENV:BHBranchName -eq "master" -and + $ENV:BHCommitMessage -match '!deploy' + ) + { + $Params = @{ + Path = $ProjectRoot + Force = $true + } + + Invoke-PSDeploy @Verbose @Params + } + else + { + "Skipping deployment: To deploy, ensure that...`n" + + "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + + "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + + "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)" + } +} \ No newline at end of file From 46ac3925f4d74fe3a712f509915a4c9d8602bd15 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 28 Mar 2017 17:43:56 -0500 Subject: [PATCH 026/348] Overhaul 2017.03.28 --- MAKE.ps1 => Build/MAKE.ps1 | 0 build.ps1 => Build/build.ps1 | 5 +- psake.ps1 => Build/psake.ps1 | 100 +++++++++++++++++++++++++---- PoshServiceNow/PoshServiceNow.psd1 | 2 +- Readme.md | 2 +- Tests/PoshServiceNow.Tests.ps1 | 7 +- Tests/Test.ps1 | 25 -------- 7 files changed, 97 insertions(+), 44 deletions(-) rename MAKE.ps1 => Build/MAKE.ps1 (100%) rename build.ps1 => Build/build.ps1 (83%) rename psake.ps1 => Build/psake.ps1 (51%) delete mode 100644 Tests/Test.ps1 diff --git a/MAKE.ps1 b/Build/MAKE.ps1 similarity index 100% rename from MAKE.ps1 rename to Build/MAKE.ps1 diff --git a/build.ps1 b/Build/build.ps1 similarity index 83% rename from build.ps1 rename to Build/build.ps1 index 60bc41c..ab87b67 100644 --- a/build.ps1 +++ b/Build/build.ps1 @@ -24,7 +24,8 @@ ForEach ($Module in $Modules) { Import-Module $Module } -Set-BuildEnvironment +$Path = (Resolve-Path $PSScriptRoot\..).Path +Set-BuildEnvironment -Path $Path -Invoke-psake -buildFile .\psake.ps1 -taskList $Task -nologo +Invoke-psake -buildFile $PSScriptRoot\psake.ps1 -taskList $Task -nologo exit ( [int]( -not $psake.build_success ) ) \ No newline at end of file diff --git a/psake.ps1 b/Build/psake.ps1 similarity index 51% rename from psake.ps1 rename to Build/psake.ps1 index ef2a930..72c200f 100644 --- a/psake.ps1 +++ b/Build/psake.ps1 @@ -1,11 +1,10 @@ # PSake makes variables declared here available in other scriptblocks -# Init some things Properties { # Find the build folder based on build system - $ProjectRoot = $ENV:BHProjectPath + $ProjectRoot = Resolve-Path $ENV:BHProjectPath if(-not $ProjectRoot) { - $ProjectRoot = $PSScriptRoot + $ProjectRoot = Resolve-Path "$PSScriptRoot\.." } $Timestamp = Get-date -uformat "%Y%m%d-%H%M%S" @@ -22,6 +21,7 @@ Properties { Task Default -Depends Deploy +# Init some things Task Init { $lines Set-Location $ProjectRoot @@ -54,26 +54,26 @@ Task UnitTests -Depends Init { Task Test -Depends UnitTests { $lines - "`n`tSTATUS: Testing with PowerShell $PSVersion" + "`nSTATUS: Testing with PowerShell $PSVersion" # Gather test results. Store them in a variable and file + $TestFilePath = Join-Path $ProjectRoot $TestFile $CodeCoverage = Join-Path $Env:BHPSModulePath "$($Env:BHProjectName).psm1" - $TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile "$ProjectRoot\$TestFile" -Tag Build - #$CoveragePercent = 100-(($testResult.CodeCoverage.NumberOfCommandsMissed/$testResult.CodeCoverage.NumberOfCommandsAnalyzed)*100) + $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath -Tag Build - # In Appveyor? Upload our tests! #Abstract this into a function? + # In Appveyor? Upload our tests! #Abstract this into a function? If($ENV:BHBuildSystem -eq 'AppVeyor') { - [xml]$content = Get-Content "$ProjectRoot\$TestFile" + [xml]$content = Get-Content $TestFilePath $content.'test-results'.'test-suite'.type = "Powershell" - $content.Save("$ProjectRoot\$TestFile") + $content.Save($TestFilePath) "Uploading $ProjectRoot\$TestFile to AppVeyor" "JobID: $env:APPVEYOR_JOB_ID" - (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path "$ProjectRoot\$TestFile")) + (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $TestFilePath)) } - #Remove-Item "$ProjectRoot\$TestFile" -Force -ErrorAction SilentlyContinue + Remove-Item $TestFilePath -Force -ErrorAction SilentlyContinue # Failed tests? # Need to tell psake or it will proceed to the deployment. Danger! @@ -87,7 +87,7 @@ Task Test -Depends UnitTests { Task Build -Depends Test { $lines - $functions = Get-ChildItem "$PSScriptRoot\$env:BHProjectName\Public\*.ps1" | + $functions = Get-ChildItem "$env:BHPSModulePath\Public\*.ps1" | Where-Object{ $_.name -notmatch 'Tests'} | Select-Object -ExpandProperty basename @@ -101,13 +101,85 @@ Task Build -Depends Test { { $version = $galleryVersion } - $version = [version]::New($version.Major,$version.Minor,$version.Build,$env:BHBuildNumber) + $Script:version = [version]::New($version.Major,$version.Minor,$version.Build) Write-Host "Using version: $version" Update-Metadata -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -Value $version + + # Update Code Coverage + Function Update-CodeCoveragePercent{ + param( + [int]$CodeCoverage=0, + [string]$TextFilePath="$Env:BHProjectPath\Readme.md" + ) + $ReadmeContent = Get-Content $TextFilePath + $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} + Set-Content -Path $TextFilePath -Value $ReadmeContent + } + + $CoveragePercent = 100-(($Script:TestResults.CodeCoverage.NumberOfCommandsMissed/$Script:TestResults.CodeCoverage.NumberOfCommandsAnalyzed)*100) + "Running Update-CodeCoveragePercent with percentage $CoveragePercent" + Update-CodeCoveragePercent -CodeCoverage $CoveragePercent + "`n" +} + +Task MakePackage -Depends Build,Test { + $lines + + function ZipFiles + { + param( $zipfilename, $sourcedir ) + Add-Type -Assembly System.IO.Compression.FileSystem + $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal + [System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir, + $zipfilename, $compressionLevel, $true) + } + + function New-MakePackage{ + param( + [string[]]$PackageFilePatternExclusions, + [string]$PackageName, + [string]$ModuleName + ) + <# + @($FilePatternExclusions | ForEach-Object{"MAKE.zip" -match $_}).contains($true) + + $FilesToInclude = Get-ChildItem -Path $Env:BHPSModulePath -Recurse | Where-Object { + $File=$_ + !($PackageFilePatternExclusions | ForEach-Object{$File.Name -match $_}).contains($true) + } + + # Create temporary folder and copy the files we want into it + $TempFolder = Join-Path $ProjectRoot "Temp" + New-Item $TempFolder -ItemType Container -Force | Out-Null + $FilesToInclude | ForEach-Object {Copy-Item -Path $_.FullName -Destination $TempFolder\$_ -Force} + #> + # Create a zip based on that folder (overwriting it if it already exists) + $ZipFile = "$ProjectRoot\$PackageName" + Remove-Item $ZipFile -Force -ErrorAction SilentlyContinue | Out-Null + ZipFiles $ZipFile $Env:BHPSModulePath + } + + <# + $PackageFilePatternExclusions = @( + "MAKE\.ps1", + ".+\.zip", + ".+\.md" + ".+\.Tests\.ps1", + "\.gitignore", + "LICENSE", + ".+\.Pester.Defaults.json" + ) + #> + # Update/Create the package + $PackageName = "$($Env:BHProjectName)-v$($Script:version).zip" + "Creating package $PackageName" + New-MakePackage -PackageName $PackageName -ModuleName $ModuleName + + "`n" } -Task Deploy -Depends Build { +Task Deploy -Depends Build,MakePackage { $lines # Gate deployment diff --git a/PoshServiceNow/PoshServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 index b23c6da..4ee6358 100644 --- a/PoshServiceNow/PoshServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'PoshServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.18.0' +ModuleVersion = '0.1.34' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' diff --git a/Readme.md b/Readme.md index ffe331b..666ad64 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,5 @@ # PoshServiceNow -[![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-100%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. diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index b2f49f4..1f94f99 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -15,6 +15,11 @@ if(Test-Path $DefaultsFile){ $defaults."$($_.Name)" = $_.Value } + ########################### + # + #Cheating here with the credentials + # + ########################### $defaults.Creds = (Get-MDSCredentials User) # Prompt for credentials @@ -22,7 +27,7 @@ if(Test-Path $DefaultsFile){ $global:ServiceNowPesterTestDefaults = $defaults }else{ - Write-Error "$DefaultsFile does not exist. Created example file. Please populate with your values"; + Write-Error "$DefaultsFile does not exist. Created example file. Please populate with your values" # Write example file @{ diff --git a/Tests/Test.ps1 b/Tests/Test.ps1 deleted file mode 100644 index 203aa2b..0000000 --- a/Tests/Test.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -<# -$DomainSuffix = 'iheartmedia.com' - -$UserName = '1113192' -$newFolderName = "$UserName".ToUpper() -$newFolderFull = "\\CIHM01SATRA\c$\users\1113193\desktop\$newFolderName" - -[system.io.directory]::CreateDirectory($newFolderFull) - -$AddAccessRule = New-Object 'security.accesscontrol.filesystemaccessrule'("$UserName@$($DomainSuffix)",@("FullControl"),"ContainerInherit,Objectinherit","None","Allow") -$acl = Get-Acl $newFolderFull -$acl.AddAccessRule($AddAccessRule) -set-acl -aclobject $acl $newFolderFull -#> - -$projectRoot = Resolve-Path "$PSScriptRoot\.." -$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") -$moduleName = Split-Path $moduleRoot -Leaf -$DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.json" - -Write-Host "ProjectRoot: " $projectroot -Write-Host "moduleroot: " $moduleroot -Write-Host "modulename: " $modulename -Write-Host "DefaultsFile: " $DefaultsFile -Test-Path $DefaultsFile \ No newline at end of file From 0141f5a6f727fd21886b620da85c4516e3a53dfb Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 29 Mar 2017 09:13:44 -0500 Subject: [PATCH 027/348] Remove Make.ps1 --- Build/MAKE.ps1 | 85 -------------------------------------------------- 1 file changed, 85 deletions(-) delete mode 100644 Build/MAKE.ps1 diff --git a/Build/MAKE.ps1 b/Build/MAKE.ps1 deleted file mode 100644 index b45cc77..0000000 --- a/Build/MAKE.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -function ZipFiles -{ - param( $zipfilename, $sourcedir ) - Add-Type -Assembly System.IO.Compression.FileSystem - $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal - [System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir, - $zipfilename, $compressionLevel, $true) -} - -function New-MakePackage{ - param( - [string[]]$PackageFilePatternExclusions, - [string]$PackageName, - [string]$ModuleName - ) - @($FilePatternExclusions | ForEach-Object{"MAKE.zip" -match $_}).contains($true) - - $FilesToInclude = Get-ChildItem -Path $here -Recurse | Where-Object { - $File=$_; - !$_.PSIsContainer -and - !($PackageFilePatternExclusions | ForEach-Object{$File.Name -match $_}).contains($true) - } - - # Create temporary folder and copy the files we want into it - New-Item $here\$ModuleName -ItemType Container -Force | Out-Null - $FilesToInclude | ForEach-Object {Copy-Item -Path $_.FullName -Destination $here\$ModuleName\$_ -Force} - - # Create a zip based on that folder (overwriting it if it already exists) - $ZipFile = "$here\$PackageName" - Remove-Item $ZipFile -Force -ErrorAction SilentlyContinue | Out-Null - ZipFiles $ZipFile $here\$ModuleName - Remove-Item $here\$ModuleName -Recurse| Out-Null -} - -Function Update-CodeCoveragePercent{ - param( - [int]$CodeCoverage=0, - [string]$TextFilePath="$here\Readme.md" - ) - $ReadmeContent = Get-Content $TextFilePath - $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} - Set-Content -Path $TextFilePath -Value $ReadmeContent -} - -Function UpdateManifest{ - param( - [string]$ManifestPath, - [string]$Version - ) - - Write-Verbose "Updating $ManifestPath to version $Version" - $ManifestContent = Get-Content $ManifestPath - $ManifestContent = $ManifestContent | ForEach-Object{$_ -replace "ModuleVersion = '(\d|\.)+'", "ModuleVersion = '$Version'"} - Set-Content -path $ManifestPath -Value $ManifestContent -} - -$PackageFilePatternExclusions = @( - "MAKE\.ps1", - ".+\.zip", - ".+\.md" - ".+\.Tests\.ps1", - "\.gitignore", - "LICENSE", - ".+\.Pester.Defaults.json" -) - -$here = Split-Path -Parent $MyInvocation.MyCommand.Path -$Here = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell' - -$Version = "0.1.12" -$ModuleName = "PoshServiceNow" -$PackageName = "$ModuleName-v$($version).zip" - -# Perform Pester tests -$CodeCoverage = Join-Path $Here (Join-Path $ModuleName "$($ModuleName).psm1") -$TestResult = Invoke-Pester -Path $Here -CodeCoverage $CodeCoverage -PassThru -$CoveragePercent = 100-(($testResult.CodeCoverage.NumberOfCommandsMissed/$testResult.CodeCoverage.NumberOfCommandsAnalyzed)*100) - -# Update/Create the package and -if($TestResult.FailedCount -eq 0){ - New-MakePackage -PackageFilePatternExclusions $PackageFilePatternExclusions -PackageName $PackageName -ModuleName $ModuleName - Update-CodeCoveragePercent -CodeCoverage $CoveragePercent - UpdateManifest -ManifestPath "$here\$ModuleName\$ModuleName.psd1" -Version $Version -} - \ No newline at end of file From 1bcbd686138fecff0742745c909955a79cee8101 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 29 Mar 2017 11:32:02 -0500 Subject: [PATCH 028/348] Pester Code Coverage Updates --- Build/psake.ps1 | 6 ++++-- .../Public/Remove-ServiceNowAuth.ps1 | Bin 480 -> 932 bytes Tests/PoshServiceNow.Tests.ps1 | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 72c200f..eb20b5d 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -58,8 +58,10 @@ Task Test -Depends UnitTests { # Gather test results. Store them in a variable and file $TestFilePath = Join-Path $ProjectRoot $TestFile - $CodeCoverage = Join-Path $Env:BHPSModulePath "$($Env:BHProjectName).psm1" - $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath -Tag Build + $CodeFiles = Get-ChildItem $Env:BHPSModulePath -Recurse -Include "*.psm1","*.ps1" + $CodeCoverage = New-Object System.Collections.ArrayList + $CodeCoverage.AddRange($CodeFiles.FullName) + $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath # In Appveyor? Upload our tests! #Abstract this into a function? If($ENV:BHBuildSystem -eq 'AppVeyor') diff --git a/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 b/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 index fa820378b54f208a442374f0b8a6dbf365658d67..413d744bb7fd79813ac274e949f6ca200aa98ff6 100644 GIT binary patch literal 932 zcmd6mK}*9x5QX1a@IUOK2R-;Bq(~`94^65^sWzd3HYw{?DaF68ezWb;1ZqI=Aj|H| zhBq^B-%P$fOKnx_MM0GsJg2D&t?}QmH_A9Yeg&q`gzxXVB_?R8y)JbTwzDu#iL?d^^CVzOq*}w-R;Ql znN6vhDcApHI7E*^3wDhTruvF`Fundt%kESRsSwbANsYr4C#{oxgi!^?{()1^oCbRO Vu}AI6ERSzEH=FGq_f7PH^EZmjj1&L> delta 78 zcmZ3&{(yOc3#S4D2=X#;O}1z9ob1D>#0+CUW7LAOs|A5#AT?mMAoWEPH;VIEgN16r FBmhMm48i~a diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index 1f94f99..6358ab0 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -44,11 +44,22 @@ Remove-Module $ModuleName -ErrorAction SilentlyContinue Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -Force Describe "ServiceNow-Module" { - + If (Test-ServiceNowAuthisSet) { + Remove-ServiceNowAuth + } + + It "Test-ServiceNowAuthIsSet not set" { + Test-ServiceNowAuthIsSet | Should be $false + } + It "Set-ServiceNowAuth works" { Set-ServiceNowAuth -url $defaults.ServiceNowURL -Credentials $defaults.Creds | Should be $true } + It "Test-ServiceNowAuthIsSet set" { + Test-ServiceNowAuthIsSet | Should be $true + } + It "New-ServiceNowIncident (and by extension New-ServiceNowTableEntry) works" { $TestTicket = New-ServiceNowIncident -ShortDescription "Testing with Pester" ` -Description "Long description" -AssignmentGroup $defaults.TestUserGroup ` @@ -109,4 +120,8 @@ Describe "ServiceNow-Module" { It "Get-ServiceNowChangeRequest works" { (Get-ServiceNowChangeRequest).Count -gt 0 | Should Match $true } + + It "Remove-ServiceNowAuth works" { + Remove-ServiceNowAuth | Should be $true + } } \ No newline at end of file From 5b5cc96326bb559f4ca1a76515c55ddc2164fc6e Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 29 Mar 2017 13:35:37 -0500 Subject: [PATCH 029/348] psake update - enabled analyze task --- Build/psake.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index eb20b5d..1684d13 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -30,15 +30,15 @@ Task Init { "`n" } -<# + Task Analyze -Depends Init { - $saResults = Invoke-ScriptAnalyzer -Path $script -Severity @('Error', 'Warning') -Recurse -Verbose:$false + $saResults = Invoke-ScriptAnalyzer -Path $Env:BHPSModulePath -Severity @('Error', 'Warning') -Recurse -Verbose:$false if ($saResults) { $saResults | Format-Table - Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' + #Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' } } -#> + Task UnitTests -Depends Init { $lines From 7882a52fca64f7eb5ab268ff6097642c3593817f Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 12 Apr 2017 16:46:57 -0500 Subject: [PATCH 030/348] Removed commented out code --- Build/psake.ps1 | 32 ++++---------------------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index 1684d13..f055d8a 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -139,44 +139,20 @@ Task MakePackage -Depends Build,Test { function New-MakePackage{ param( - [string[]]$PackageFilePatternExclusions, [string]$PackageName, + [string]$PackagePath, [string]$ModuleName ) - <# - @($FilePatternExclusions | ForEach-Object{"MAKE.zip" -match $_}).contains($true) - $FilesToInclude = Get-ChildItem -Path $Env:BHPSModulePath -Recurse | Where-Object { - $File=$_ - !($PackageFilePatternExclusions | ForEach-Object{$File.Name -match $_}).contains($true) - } - - # Create temporary folder and copy the files we want into it - $TempFolder = Join-Path $ProjectRoot "Temp" - New-Item $TempFolder -ItemType Container -Force | Out-Null - $FilesToInclude | ForEach-Object {Copy-Item -Path $_.FullName -Destination $TempFolder\$_ -Force} - #> - # Create a zip based on that folder (overwriting it if it already exists) - $ZipFile = "$ProjectRoot\$PackageName" + $ZipFile = "$PackagePath\$PackageName" Remove-Item $ZipFile -Force -ErrorAction SilentlyContinue | Out-Null - ZipFiles $ZipFile $Env:BHPSModulePath + ZipFiles $ZipFile $ModuleName } - <# - $PackageFilePatternExclusions = @( - "MAKE\.ps1", - ".+\.zip", - ".+\.md" - ".+\.Tests\.ps1", - "\.gitignore", - "LICENSE", - ".+\.Pester.Defaults.json" - ) - #> # Update/Create the package $PackageName = "$($Env:BHProjectName)-v$($Script:version).zip" "Creating package $PackageName" - New-MakePackage -PackageName $PackageName -ModuleName $ModuleName + New-MakePackage -PackageName $PackageName -PackagePath $ProjectRoot -ModuleName $Env:BHPSModulePath "`n" } From 5489c20c39083e0000729378433baa48f4a1db3c Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 13 Jul 2017 09:08:48 -0500 Subject: [PATCH 031/348] Changed function dot source method to io.file. --- PoshServiceNow/PoshServiceNow.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/PoshServiceNow/PoshServiceNow.psm1 index 9cb7a74..ef1a944 100644 --- a/PoshServiceNow/PoshServiceNow.psm1 +++ b/PoshServiceNow/PoshServiceNow.psm1 @@ -15,7 +15,7 @@ foreach($Folder in @('Private', 'Public')) # dot source each file $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | - ForEach-Object {Write-Verbose $_.basename; . $_.FullName} + ForEach-Object {Write-Verbose $_.basename; . ([scriptblock]::Create([io.file]::ReadAllText($PSItem)))} } } From 75a3f8cf49b2fe6503c5fbfef10b807b54b8e927 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 13 Jul 2017 11:02:17 -0500 Subject: [PATCH 032/348] Simply formatting changes --- Build/build.ps1 | 13 ++++++------- PoshServiceNow/PoshServiceNow.format.ps1xml | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Build/build.ps1 b/Build/build.ps1 index ab87b67..930afe3 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -15,17 +15,16 @@ $Modules = @("Psake", "PSDeploy","BuildHelpers","PSScriptAnalyzer", "Pester") ForEach ($Module in $Modules) { If (-not (Get-Module -Name $Module -ListAvailable)) { - Switch ($Module) { - Pester {Install-Module $Module -Force -SkipPublisherCheck} - Default {Install-Module $Module -Force} - } - + Switch ($Module) { + Pester {Install-Module $Module -Force -SkipPublisherCheck} + Default {Install-Module $Module -Force} + } } - Import-Module $Module + Import-Module $Module } $Path = (Resolve-Path $PSScriptRoot\..).Path Set-BuildEnvironment -Path $Path Invoke-psake -buildFile $PSScriptRoot\psake.ps1 -taskList $Task -nologo -exit ( [int]( -not $psake.build_success ) ) \ No newline at end of file +exit ([int](-not $psake.build_success)) \ No newline at end of file diff --git a/PoshServiceNow/PoshServiceNow.format.ps1xml b/PoshServiceNow/PoshServiceNow.format.ps1xml index 7fe4a02..4af5be2 100644 --- a/PoshServiceNow/PoshServiceNow.format.ps1xml +++ b/PoshServiceNow/PoshServiceNow.format.ps1xml @@ -58,7 +58,6 @@ opened_at - From e932b32899356aa61de6818fc80a32ee1c1e9942 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 14 Jul 2017 15:24:34 -0500 Subject: [PATCH 033/348] Fixed format name from PSServiceNow to PoshServiceNow to match the format.ps1xml file --- .../Public/Get-ServiceNowChangeRequest.ps1 | Bin 7524 -> 7528 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 67616e60f656e4ffd4ba48bfef85cf288bd9cbb8..eacdaaab09fef8c16837920d555f5444ed89454e 100644 GIT binary patch delta 20 bcmaE2^}=eyD;d^&hGK?{$@RjblVno>Thj-V delta 13 UcmaE1^~7q!D;dV%$?s(<0WeSoVgLXD From b7ff27f186fc71464ae05ba14082233b18c61741 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 14 Jul 2017 15:44:59 -0500 Subject: [PATCH 034/348] Fixed object for io.file scriptblock to use the Fullname property --- PoshServiceNow/PoshServiceNow.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/PoshServiceNow/PoshServiceNow.psm1 index ef1a944..ddff9d4 100644 --- a/PoshServiceNow/PoshServiceNow.psm1 +++ b/PoshServiceNow/PoshServiceNow.psm1 @@ -15,7 +15,7 @@ foreach($Folder in @('Private', 'Public')) # dot source each file $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | - ForEach-Object {Write-Verbose $_.basename; . ([scriptblock]::Create([io.file]::ReadAllText($PSItem)))} + ForEach-Object {Write-Verbose $_.basename; . ([scriptblock]::Create([io.file]::ReadAllText($PSItem.FullName)))} } } From 917b2bf8355f149cb1a9065ceddc27c1b1bfe4ef Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 14 Jul 2017 17:57:45 -0500 Subject: [PATCH 035/348] Updated CodeCoverage function, Replaced BHPSModulePath with BHModulePath as required by BuildHelpers module --- Build/psake.ps1 | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index f055d8a..e967ec5 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -32,7 +32,7 @@ Task Init { Task Analyze -Depends Init { - $saResults = Invoke-ScriptAnalyzer -Path $Env:BHPSModulePath -Severity @('Error', 'Warning') -Recurse -Verbose:$false + $saResults = Invoke-ScriptAnalyzer -Path $ENV:BHModulePath -Severity @('Error', 'Warning') -Recurse -Verbose:$false if ($saResults) { $saResults | Format-Table #Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' @@ -58,7 +58,7 @@ Task Test -Depends UnitTests { # Gather test results. Store them in a variable and file $TestFilePath = Join-Path $ProjectRoot $TestFile - $CodeFiles = Get-ChildItem $Env:BHPSModulePath -Recurse -Include "*.psm1","*.ps1" + $CodeFiles = Get-ChildItem $ENV:BHModulePath -Recurse -Include "*.psm1","*.ps1" $CodeCoverage = New-Object System.Collections.ArrayList $CodeCoverage.AddRange($CodeFiles.FullName) $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath @@ -89,7 +89,7 @@ Task Test -Depends UnitTests { Task Build -Depends Test { $lines - $functions = Get-ChildItem "$env:BHPSModulePath\Public\*.ps1" | + $functions = Get-ChildItem "$ENV:BHModulePath\Public\*.ps1" | Where-Object{ $_.name -notmatch 'Tests'} | Select-Object -ExpandProperty basename @@ -114,8 +114,18 @@ Task Build -Depends Test { [int]$CodeCoverage=0, [string]$TextFilePath="$Env:BHProjectPath\Readme.md" ) + + $BadgeColor = Switch ($CodeCoverage) { + 100 {"brightgreen"} + {95..99 -contains $_} {"green"} + {85..94 -contains $_} {"yellowgreengreen"} + {75..84 -contains $_} {"yellow"} + {65..74 -contains $_} {"orange"} + default {"red"} + } + $ReadmeContent = Get-Content $TextFilePath - $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-yellowgreen.svg)"} + $ReadmeContent = $ReadmeContent | ForEach-Object {$_-replace "!\[Test Coverage\].+\)", "![Test Coverage](https://img.shields.io/badge/coverage-$CodeCoverage%25-$BadgeColor.svg)"} Set-Content -Path $TextFilePath -Value $ReadmeContent } @@ -152,7 +162,7 @@ Task MakePackage -Depends Build,Test { # Update/Create the package $PackageName = "$($Env:BHProjectName)-v$($Script:version).zip" "Creating package $PackageName" - New-MakePackage -PackageName $PackageName -PackagePath $ProjectRoot -ModuleName $Env:BHPSModulePath + New-MakePackage -PackageName $PackageName -PackagePath $ProjectRoot -ModuleName $ENV:BHModulePath "`n" } From eac536438ed9bd225830e74faa84d6d22056a8a4 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 14 Jul 2017 18:00:19 -0500 Subject: [PATCH 036/348] Updated MDSTools cmdlet reference, Pointed Import-Module to psd1, Removed unnecessary tick in New-ServiceNowIncident, Temp change to allow test to pass in my environment. --- Tests/PoshServiceNow.Tests.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index 6358ab0..5180746 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -20,7 +20,7 @@ if(Test-Path $DefaultsFile){ #Cheating here with the credentials # ########################### - $defaults.Creds = (Get-MDSCredentials User) + $defaults.Creds = (Get-MDSCredential User) # Prompt for credentials $defaults.Creds = if($defaults.Creds){$defaults.Creds}else{Get-Credential} @@ -41,7 +41,7 @@ if(Test-Path $DefaultsFile){ # Load the module (unload it first in case we've made changes since loading it previously) Remove-Module $ModuleName -ErrorAction SilentlyContinue -Import-Module (Join-Path $moduleRoot "$moduleName.psm1") -Force +Import-Module (Join-Path $moduleRoot "$moduleName.psd1") -Force Describe "ServiceNow-Module" { If (Test-ServiceNowAuthisSet) { @@ -65,7 +65,7 @@ Describe "ServiceNow-Module" { -Description "Long description" -AssignmentGroup $defaults.TestUserGroup ` -Category $defaults.TestCategory -SubCategory $Defaults.TestSubcategory ` -Comment "Comment" -ConfigurationItem $defaults.TestConfigurationItem ` - -Caller $defaults.TestUser ` + -Caller $defaults.TestUser $TestTicket.short_description | Should be "Testing with Pester" } From 2a8c1f64c7edd0d75e8c37c2e6e743c64d2b66cc Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 17 Jul 2017 09:32:31 -0500 Subject: [PATCH 037/348] Changed dot sourcing back to $PSItem.FullName. The io.file method strips AST and breaks Pester's code coverage. --- PoshServiceNow/PoshServiceNow.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/PoshServiceNow/PoshServiceNow.psm1 index ddff9d4..c666d6e 100644 --- a/PoshServiceNow/PoshServiceNow.psm1 +++ b/PoshServiceNow/PoshServiceNow.psm1 @@ -15,7 +15,7 @@ foreach($Folder in @('Private', 'Public')) # dot source each file $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | - ForEach-Object {Write-Verbose $_.basename; . ([scriptblock]::Create([io.file]::ReadAllText($PSItem.FullName)))} + ForEach-Object {Write-Verbose $_.basename; . $PSItem.FullName} } } From 7b2a5db6f1d4593c3e5edf53525b0724d006b404 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 17 Jul 2017 15:57:53 -0500 Subject: [PATCH 038/348] Replaced % alias with ForEach-Object --- .../Public/Get-ServiceNowChangeRequest.ps1 | Bin 7528 -> 7556 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index eacdaaab09fef8c16837920d555f5444ed89454e..33ed37bf1286b065cf5b5522b79c3fb7c8e93940 100644 GIT binary patch delta 41 vcmaE1)ndJ2k&LVxLq0@~ From ab79ac9ba03308a5e7f5be69cf2fc3084f9536bf Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 17 Jul 2017 18:04:04 -0500 Subject: [PATCH 039/348] Incorporated PR#12 that wouldn't have merged --- PoshServiceNow/Public/New-ServiceNowQuery.ps1 | Bin 2752 -> 2760 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/PoshServiceNow/Public/New-ServiceNowQuery.ps1 b/PoshServiceNow/Public/New-ServiceNowQuery.ps1 index 712f5bffaf6d4889fb7d4bc9064a231acc661bde..453f46576a4532b60077189594f99fd44081a1ba 100644 GIT binary patch delta 77 zcmX>gdO~!jPGWhdt`Nli9mJcTT_S&8WsBTQiPN9Ia62dKk#@;Od{ J&3jl`SOM6J7-#?h delta 62 scmX>hdO&o-FV+% Date: Thu, 20 Jul 2017 10:47:10 -0500 Subject: [PATCH 040/348] Removed Get-MDSCredential shortcut used for personal testing --- Tests/PoshServiceNow.Tests.ps1 | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index 5180746..5617df0 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -15,13 +15,6 @@ if(Test-Path $DefaultsFile){ $defaults."$($_.Name)" = $_.Value } - ########################### - # - #Cheating here with the credentials - # - ########################### - $defaults.Creds = (Get-MDSCredential User) - # Prompt for credentials $defaults.Creds = if($defaults.Creds){$defaults.Creds}else{Get-Credential} From 41a0e0721bf11c824f93268dc25b02aa157d6f7d Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 20 Jul 2017 10:47:51 -0500 Subject: [PATCH 041/348] Ran build for v0.1.35 with subsequent ReadMe update. --- PoshServiceNow/PoshServiceNow.psd1 | 4 ++-- Readme.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PoshServiceNow/PoshServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 index 4ee6358..fd79a8d 100644 --- a/PoshServiceNow/PoshServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -1,4 +1,4 @@ -# +# # Module manifest for module 'PoshServiceNow' # # Generated by: Sam Martin @@ -12,7 +12,7 @@ RootModule = 'PoshServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.34' +ModuleVersion = '0.1.35' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' diff --git a/Readme.md b/Readme.md index 666ad64..1e0b000 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,5 @@ # PoshServiceNow -[![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-100%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-74%25-orange.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. From 469cca80c0ea2cb721a7411ffdb4cb7b06d911be Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 20 Jul 2017 10:59:59 -0500 Subject: [PATCH 042/348] Removed comments and testing edits --- Tests/PoshServiceNow.Tests.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/PoshServiceNow.Tests.ps1 index 5617df0..5ff3788 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/PoshServiceNow.Tests.ps1 @@ -1,8 +1,3 @@ -<# -$moduleRoot = Split-Path -Parent $MyInvocation.MyCommand.Path -$ModuleName = "PoshServiceNow" -#> - $projectRoot = Resolve-Path "$PSScriptRoot\.." $moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") $moduleName = Split-Path $moduleRoot -Leaf From 9778a1933e45ac1a1caffb74e4b1ed116bd7f8f4 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 25 Jul 2017 10:06:50 -0500 Subject: [PATCH 043/348] Saved psd1 with UTF8 Encoding --- PoshServiceNow/PoshServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PoshServiceNow/PoshServiceNow.psd1 b/PoshServiceNow/PoshServiceNow.psd1 index fd79a8d..682111d 100644 --- a/PoshServiceNow/PoshServiceNow.psd1 +++ b/PoshServiceNow/PoshServiceNow.psd1 @@ -1,4 +1,4 @@ -# +# # Module manifest for module 'PoshServiceNow' # # Generated by: Sam Martin From 9ba5a3d6fc31b596e52e299f63b141c2ce574ee7 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 25 Jul 2017 10:14:26 -0500 Subject: [PATCH 044/348] Changed encoding to UTF8 --- PoshServiceNow/PoshServiceNow-Automation.json | Bin 1604 -> 801 bytes .../Public/Get-ServiceNowChangeRequest.ps1 | Bin 7556 -> 3777 bytes .../Get-ServiceNowConfigurationItem.ps1 | Bin 7756 -> 3881 bytes .../Public/Get-ServiceNowIncident.ps1 | Bin 8326 -> 4166 bytes PoshServiceNow/Public/Get-ServiceNowTable.ps1 | Bin 6984 -> 3491 bytes PoshServiceNow/Public/Get-ServiceNowUser.ps1 | Bin 8214 -> 4106 bytes .../Public/Get-ServiceNowUserGroup.ps1 | Bin 8274 -> 4136 bytes .../Public/New-ServiceNowIncident.ps1 | Bin 9202 -> 4600 bytes PoshServiceNow/Public/New-ServiceNowQuery.ps1 | Bin 2760 -> 1379 bytes .../Public/New-ServiceNowTableEntry.ps1 | Bin 5690 -> 2853 bytes .../Public/Remove-ServiceNowAuth.ps1 | Bin 932 -> 465 bytes .../Public/Remove-ServiceNowTableEntry.ps1 | Bin 5246 -> 2622 bytes PoshServiceNow/Public/Set-ServiceNowAuth.ps1 | Bin 814 -> 406 bytes .../Public/Test-ServiceNowAuthIsSet.ps1 | Bin 298 -> 148 bytes 14 files changed, 0 insertions(+), 0 deletions(-) diff --git a/PoshServiceNow/PoshServiceNow-Automation.json b/PoshServiceNow/PoshServiceNow-Automation.json index 7d5081887974aeb8bb77e0a4432220699a15f784..3e3ea2278df9fb2f339cb5eb1e89bfaec086a5d2 100644 GIT binary patch literal 801 zcmc(dO$x#=5QX=J-a)b!58zHjp$oN8>qcCJcGN(cl$q30ig!1$)cU_r#HATdI#sQ{T08}`;s%eCvSJgWnms06FrKx&0sE(!V%l11*uarsIy=NZ@@ ziwRJ<`hLW+%AplS6&c6|kwKw$tlM?G`t;tV!Qu;(Atx#|raw0MWt0)%K_oEOWsKtQ zR-Yx_-g6WND?qYCU$m_)?W~s5q2?-Cg>pUU&c2S>3r#gvkkdZ@UNy2(b`vW_)9!Ra{t?)@ zyq?X>YWmnzByzgQRs5YZkmFIL}l|8+s_-9?5+XRK$NEz{9 zlg+fJjFX4GQWI*`nNIU8d*=NKm$ByKhL{|}U|=m!jioKnn}%oSENde{Q#uV4L0CmnkF~7E=G>s+0IHd_}@9lNt~1- zhIn8a^ren}T<*Sn_uY9>%G7ct;T78C6!i^Hai&&#Ig?lT9L79h)FP81|`31|Y?I9h77rIum)gT|Ii zdl4P+g4^k{r$3?LYi4rG<^myA(lRa`3yUVReKx!NHb5y0H%yQuG$3LIMM?TlFq`Ip zUs!5I1@Vdt0dr@rn3FnWu;Mm{-P!)X!sxt3^dfrepgC~JOkdo7TjS{;A+OcSc=(&o z_8<83b>K_6p5)r!PHgH+ZDgUQtj@{%eO(VJy;Mr7P91*=-xlPOC}PEpzf z@d@#d$jLyetuApi8P(<6Nj4K=vt;jk5a}>U$8_w@4Hf&mEAw$T`enhNkj!^I#2MKf zl#ABWnXMhiTO(oH#IPjt>@~8_ea0s zCF%;MFvC@^5B0N2(^EmW zyPfbWT|2P0A;4~`^pZM*H49c-P)8ciuI z1vqT9&uW=T{NFgO+wM#4`|dF$KK{-~14muZgK7Vm4ALyD4yTiz$35?TXy5!FQa@ft zw#3TGR0*%^D%cj__2MK> zXr&=ksHQa!UtinT$H&JvKY#S)QpVDiL;;AL?agF2(@4L9$N9na}%4g}o z>Ktzl@&6UILy2J@$TxW`k8st$3)n^YA4xOw-j=Vx?k&o@@Hl|S5YJ;{&%25A@tdHG zPkmT~GL)WqH!>s`d$7W={mJblUFVnvK ziIz1QyNK-sEiuL$Kn&-#sx{&%GN?GmY}DldPdeML%zQQAjWJ~udvXfD3H&|r&YO!# z7kgXqA7y62qK>H0)`-h+)Ql&B=zZfvp&IL7jiaeNvlyi|AS)_rw(l{sE-#@*@1|?O z$9OA1$=}0#gq3xTvAF2ZuC^uOtMs8y*UzHF|24#`qPGkkgZXE{{YP`E(zBH+2mX$M zNuJ_VF>sv`qXDi|8)S23?~c((c8}zX zr1PHed6MA1Rm?*iP2*BN?tDy{mtnr)(nO3WL6UNi+Y$ zsQa@Y^^$B*u|CJfRqS8M|5Jps2=&FoAJt=I*7nS4^Woz->kc>@LUpEXR>fXVgKKqte5BvQ1bTj*tzR#sCpO{jqmv?JmRN%)iHoLppcd2aDeaiaUaDKKagO2&!1n zS9ghpG@nw$Ts0PEpELig_!I-@$mdu0G2*qV^!JEcu6&z4n{T#@k#*m!fWJ1N{q&of zerM}~HK|%ACcjJt$*(N-OlZHxG5cp(QO|@aD_UDB%9K|-@WJnh+(+F$6vvb0?(e9# zgWgcnYSxkaW%|X6$f$#v*U--xc4^5Pm|S~rzr@9`dV^lYhP9a6XO5H^{Wfayyz4{h f8rU-(?IG%>W98{2%aQE8&9nP>+8rI^ptXMiS5U)b diff --git a/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index f4af8c3b5d7de3c62a64766080b1fbd5f773ac02..a4941f120b83585f36bf1b7ce4ae2d35930d3214 100644 GIT binary patch literal 3881 zcmeHK+iu%N5Pc7je;CLFNCTqVegFZxQIZCTWhKhxK@f^1IW#vQm%?&sg>VAoGt%G7 zmvn~9tED0?`d}cb9>gVgXL#mt_RMTjsmRDe!E-eJ8ug8ga9Ql16e^L|l@>hr!e9=! zj~@a3c0!BXvtzzLflCpkQXwdjBNPdk6d{qA#b633bc`CpdN9~D9?+ona-m{j3S9?I zBC--sw?~()_?2w1Mzf?*;I4NV$)qNb3LEs#_W^#QAVf3+8>&;cOsLN z21vAeGY)<>hZ)5`n|#d)vpsWx%LYvFKo)1@N10bSs45RB`-oj4ng}jABQ=^zt6}*M z&8<{s>%5e?G{JAb{zDr6AmS9+EJ`u$Lx_9Wbn9F)HBXtD;QaRUojmy$qwm)GImvwA zKD;5HlXB4^T^43pW!aT}n(s{QP1dZ|Pc+7;j1<|Z^KeF8P(MG1afx{#z-ZNkKc+-C88}Unbx=16uH@sdW@(&net81$GsW9F1j_8G=6T zn%^{{;oFNF<#G6DBwg@rNNv1+Q;)%xW$-7v1DxrtKY}xYW|4fh7o^U)fqpD+hakY` z`aR8^zJ2-HVmfsC?aN>Dja8=2cH6yt zz}}%+t=EPHTgR8kZ8-R%45S)WY Q_7m9tw%g~AAJJC(8`vV?H~;_u literal 7756 zcmeHM+fExX5S`~reQ)0^h?F1^+I|2M6evaFRxa&BR8=7)kcuQIyA&eIueUwN6DRhr zHw`LP1&t8dwb%C8tyiBeS#@$Abt)Hm?9i?7$RX4|w- zcZPm_sgL??;jJkh^uLwo@(fS?yF?qd>qsT2ci-pHZU^5Ra*k2E7{lO~?fKS|7JgHF zV~KK`av`U-u4ljZQQ|y}oX8+5p(f)waAj;=!T5E^ImK@ZDSh-^mJ%e?F@AzJ3-b9M zqwS-guF^@M_EKm~SF$W+=<^bF4XmLBX{t%CcdYw&qxB_d|L`+7wkwNC-h=kO4(IYW zB&#+yq1zrLQOB#m5BGJFv;-~s78PgMjgsu4q`Upr?pJw)l(H;FcgshjkGOS=+7EQ^ zutqGX45IN2xT?rHS|-@1SC}=Q3sG4!obk*O>5mO(A1xx=LpEqy=1Z~fbEBP~1HKH( zy8m+%&So)Y^O&Qq9JU;Six5kWya8%EI5%Y3u6>?B9u}aUrdy zZ>fEY?5sACr?%C=dmz_eS^f->*u-fw7R@{{e4{1i*aod{teg~m2PjwId9?9q)r_On^LQ#)KL;X0jM5_@D=KO>MwnTa75Jcc!!uCCr~eM~ zeVnXoti?xvc-m%&pX3$By!mPT@5jdOzeBwG@s6PrF#j~T{{)U?WWrzd9QfM>CdtC; zG4PxbqXtiU8)S23@4EGooQ*gI=O&11F3^HJ9kM;SncUvQS2DEvC|L{Q_lcd=nOFVv zylO^u^a06JHsQ$cq9rUrCyh%QGP4XO4iPYu2#{0(g zj3j8c^4W)@p zp7SUbf*`uz2yTr{A`k$wHZ2UdmvUai%IC^@lxT->Xr- zmi=P>F6E8uvtB{iEBn>giT}s7ceAq+6nMC);g_BKKGvI+t^O9&c)x8I40ItchR5eQ{KJlwH()D%z{#@ zv2m5xiKybQzTV>q$=J3 z(d!Cw^Iya4RaSb)N#R@uBdz#W&A;EF-Ug7&`E+Dy=!@1dH)qfI z{NY3Vhg#KLsK^Tw>S&r-zBG$cvvYCxJT>^B%KW7niv za<@aZKU}{*<`(Q9v81!+-e+e%jTW*iIl!#PcJe!rvWm5wf?0goj3T&Wx;l3jrqM#l Y?&D-#`RJ$JaW@ELFqYl?*iO0X7w-bzu>b%7 diff --git a/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 b/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 index 910b89272f61adfba399d879bdc83f35e2be6b44..11d35ac57071184548116d949df98df23fab91e6 100644 GIT binary patch literal 4166 zcmeHK?QYvP6#ZYI?{H@ekOD~A_5cFn)m>MhalAO)ei%kUOH{={q70IXt7QfH813uz zNp`O&nNsW_0S2rK19P!Y6Nq3(7NzAoQPw5My4+$4BD+X5609jL6*sk# zZunQtt&nEpy%MD`@sB_JLmK|VbZ*$T;E+_(Fd-=m%dWC*HB)_Sz>vN9wLI*0PTKZOlFf?Zv}DgMi8vXhBlc%+F6NPtsb@5JU0 zDSpiEA9Q=T^$w;D4x635@P4hiY9NLM-w({SeHwLk5qjSU_Q}EFbT8a}t8TS)5y*S`$O=LL-39s_0lzk>-MyS`^XHs UBGQ5H>_*uWKwmXapI~+V4M5~MlK=n! literal 8326 zcmeHM+iuf95S?cv-r>!(k&;TJzz0O4+>vN0w7^4zP?|Il)FhSdQo`lefpd1U^{zb* zsQ{ruR5iBOd!0FZ_RRSEx1pTKMEa7;NT#?;W$0p&Vf( zmQCIJ)Qy|s{y=8t2wf@Wz*TSsE%e{RI0O8$rxa~F(!dBk^q-;5hP*yUZ@XxxtMnt# zQaLQ7E9poRwmU{yA8Qz5w7VE};?`T(`N7%xGSvV5GkD=vW{vz5)_d<}m;aHG)fx|B z+bKq(jkka?`gPGdGt@{OD&E2y4S9+uqAZm=&R`R z)A`Ch+7)#~g^osCz6HWsat}2#`0xhi&+CRc)(Ualy~O-QL)=S;O>!Brbm;glhu_!E zJii8fC3sfvB8e=XKcRj#t$%2YqMYJL~L#eVQ zOLNpt(Z=e1h1-jYTQXGcIP!@@#t2Uxxg|Hx$%c=BtqiQ3<9Yy==Be9vClyOLiswR} zpW&Gup3VOJCi3)@O`sXb`X}g-r6Cf@-HAgpcMR{i_tgKVzs-E$hrpAiFaZU!xWgc{`OnC;2UME4=ylIvBYluwYb zjkQ-->g1xTlX_Ln_>P)@s(LMmzP-w(W;nu|`dGNEvZ<{LB6JoQ>rN+nef<#s1rp zPe2-D2Wornz3Dt!@R=Jcx5e|O$ZpleGwMY~#;TS%6Y7f$f2R&50~h)Gc;?p-WZ9)_ z?DpjtU|BuGHT`_&*P-}#?ft6WuG{sNH$%&5WEYk+WW~cB(48Qr&k~7SY(aTsi z=PIFxuU>rCC}`8vT$@lWd-#v-tbS?9l_a*>GPAszT$fl!c9Gd;jxX*j9#cI~wh`yH zhgJD#ho|?pTa$Xm`>gwm>ks>U4Br!7I%}e#Jo9C&P+rM%%(^&NzW`5LSj)g^1p3H- z{|RT}cgHeTXgEJEwiWk7xF@&+IWPZBN#iIg8O;&-`Cf}!g}Hy8y?pjH*}F2}57?kM A3;+NC diff --git a/PoshServiceNow/Public/Get-ServiceNowTable.ps1 b/PoshServiceNow/Public/Get-ServiceNowTable.ps1 index 48667cc37d5efc4562647de426cbb95615a3b87a..b78eba08d3460256f50d4152a67329461fecf2d4 100644 GIT binary patch literal 3491 zcmds4QBNZ`5PnDEKa4`8UDWKRv~N^VODSAWIszr3RfP~WyA$HOU3+VL6VlWD_m1sN z?BpoDK2;(wY~r2q%r`UNe9T%=7%m08L6c2TEqH-rxty|x3itOu?(YG8ZZBKYv}U?$ zFugrdimmPr@BGmfQ>^xnssCdQ4q(h`1UUmUM=;hIEHP0Cf3~PrTs%UG`C|@T6ud-X z^kFc*ZLCi;s8Z+MK26YAkE3MLV8LgrQz-YUfQ)uLM3@`X91n*}{(_QdP92GQ0Js4UJ33#m#CM$)5cl?boDmY(Fo-1Xn_ znw!zl*E@jxHb!xBWSg@)^P0gwe9a;ElR?NA; z?&S4h_baP7F$~hkr#+)u>`w(1Y|v>0x#-vQB_qq|_^dWwkx;Q{TYa8UgJ$#w+|IYenvB0Kq= z{MFL7qop8;#O;0!D+Z+7F;GZh7#CfNO3;2A&H3%X4AOpZ1sTywUr-x% zGNIEYU9%Mg^;L%(j4aX%RAwqk&)6fs-XQXqZ{E&M^i@SgnBtRx>|CmXRF8FQKT&~0 zAJYY6TxMP;z+^@ASLcK!d&HUsH4i1vgx0aB-A`bo|q&uFOah$-x|~qa-(gLuL!L6U*lG*>bEkml`uNgxiaHjiR%X4`M8StI-W{bfg1%R1$KmpDtOGtfNs`^8Q+AP^?b1z? z#z=OcMty1Kik4^Z?5V)U62LLQ@3Muu)dorlk~+GR$1_<~a%pK`hwqQ!4*^FxoYHdX zIC2*XDC)AJ!J-$x$-%a@m5;QqKjR-_n@%yW`G;)2-LgSZHj)&Aqn=_js=cmpHj@lj zvS}-~kch;cboHR|HIOoK}wufU$*SCX0W}zc|JNAZ-(1u>KQ{vu>H-+@A zSjZ2UT~kY5kXDib5fbdxXW`TzX7C literal 6984 zcmeHMZEqVz5T4IS{D+fc$*E`@3g3bv2%&FMn}o&zp$G-nb{f<81)megp#F8>d1k!X zU3bn24V6HOEc@>Ec4ud2o_Y0Of1b*P45cGe>B|Urg*=rWo;KtV*NI$Wyo0+vyq!r) z+VWb?@%*WLB7f*_fi?Ub%RXpLWvss~nd7b}>lohwoe5UXtOK{mRc zJ%zbzShc5fd$=3PDSoGNhFy3KoE6}+Ck;^L_;28b=a}OhLwSRdbv!q5*Tg-?I{58k zYzP`9_)ED9J0IgLflo?@6xSv49>yrM={1kr;NnoFz&%dE!>-DBh*?qMPw=h>nRc;z zLmq;w0rnc=xeZz)<$YV~Sl`C15_6Yjcy}(3l&;6!KJ@+Tg5SnR*x4lZ6ek;DC!TOe z@pA@QRG+hiWG1S;H^5Up!R13&f1Xa)An6i1DHpmO$Vq~hBGI_vBx3DUwL&dTLBnv^ z#+_#|1!PBzjTB>D%!-KQ{_z|{Cbdh{o?)Dpv?ZJP%y81T_%`)@w8q1I#0u ziR3GcjX`59UxP{?Us~+8JkB^dk?*f<;{?1%PVTK>2uY%-#+CI3(TBt61Z zJ>(13H+{jjJd)25XQ)3f0(ZEc)rKoe+zd%sE(OeF-G<@ zGENcSYIvHc?rT6`Ey-#4TwsLQILGz&vH!aaU$(QMi}_c~nwVR8*zv~Jz{{?ByO0_7 zm9ql8Ge#4sW(94Gn4Qqlm@C_f!+Sp`C|pjCos9D1Wtofu?`N5(QQiB*yC!pBX4H7b16NH+MylCzlWR0Jp8+$p6ij zUxng-%l4nCR9WSOs=dnUJ#D6vvwA%pSzB~4sAb}0*@Fk|`F8#a-s=$cWYBI(nKeAC zw7Ofz7wDN-wo=E{ykXu=$onO^XX`9b&7MMvw*vVZV-b5ZmpIJ?GHc<<`ZHlwTD=t& z{53VY8lZbmC;VTUX1z_UD2#M9TMGRV1(wW#%nJb!E_*aMvzsHT+^D`wW; z%n$~sSq+zM*dm{;Bhy^;19B_pS^Vfxt)C`5K4W)o-{y&e9G9h^>u>ehLp-6r8i*xU z!Iz5~zJbxt@b$6Nbfeo5cnJyIIFF&TcDf?_^;uwQ)PCzN?hqI=lgGh8XrcrlFhl9COIc6d6&D zs#RWL`P{x%h`4%I8*aIH@>ZAG*=~>UI;=GI?EL+LFExp$7_7o%j#OVV%+n_DO{_d? z@YYwFk1^l03}6f6h5UpW7r3&=LG7>(We0kiuC66>A3)#9JRo-59xVME5-lm5g5BGk z_jqoLktw}Y68YZg8_JdcA6PydG{h&bOIJq(w1{FJ<0kJ|L#&Az+9uB1g6^!ZV;WC+ zNq1!wehvg(LW6I?%?4^M^O7%>H+GI#LvLJj6nWclt3rA>k6+KHk#3MW*Ts9%rgad1 m{0;w7S?6I4d=gJq!<#qR#J?YE>_wN=`cf diff --git a/PoshServiceNow/Public/Get-ServiceNowUser.ps1 b/PoshServiceNow/Public/Get-ServiceNowUser.ps1 index bf83b839273305b8dd3f6d022d6343d456e5f06c..d5065dd50ab1e6b0bfd92346c0d211ee439ab9db 100644 GIT binary patch literal 4106 zcmeHKZExE)5dL1E|KZ>WkOD~A_5%dOtGjMM<9KzteK3rHmQEE1y%;1FSIzq0cPC1w z6njX30V~kXUrb6o>h9s)a}TqoN{p;4c!MTdqq>&~F6+a4jq2g$3!vX#C{YG>%<~Jl z5lJp9gi4eMbp|F!$Rrjim>O!8qJmxP3^v^kXix>Es8V5S)y7^X3XPZBv&&ZeNj6xc zS<)!>*LzH4*1oE%3Oj#);_qqy*&9$m&iHosC++flV{+q7QSU@CZ%jTl(?-ea!`8dy zuzzf0pF#0M7nU1cz(OkPJ)_nEMYa$uP$%Ebb#m#}e$|-$CJISufCOtWfTknRUdCkbg*AJf`<>|jdUeyO};qQ;_f8aNdfhUgV zgw|)U|2;=)R74I6s@gCy=)68a-cVDb^cHDX5vkPsLbOBL(^iIFF{2CxVhiFMp_2(! z8`a<}oOPX>DO(i9dCFc`5XqRRBlg+uF=M|{m||t5D4@~A7<3$hnkzp_s5S81sS$t? z+(&T`97j*egpfMKQF+{vJCjZ`1i7ruvMGvN^}5`fHkhngt)0gs(c(EL-TRQ-bq-&^ z9qFU@@7_X2smEH$*#PI4s1hXhWD@S6`0~N_t=Gjc3X=kP6yN+)qYy|M)zlVPN;;th zb*Hq(eTG6*++9KvmRcXENrzpZc>*Bk%jS6OXA^4b0&-4nV1T-mr%bD==QYGs=h5zE%op6ir8O#z>>PlmE)Ae$$?Z&&_OWi@Sm9SobFx-fj? ioh{A3V4kLtwFdjgp`W_oojkIzTRA_}z{?j@Ykvc#BO_w~ literal 8214 zcmeHM+inv{5UppV{fAa!DUP%byB}bQEO!Y)AYu2xS|P_5FpA^IGa;BPzYd(!<@R*X z)C`UQtpZjQ&-7*bQg!;&r9Xcf%Y~fDKysPL3~x>z$_S;79N{^acc>rW?EtNp@=`Ki zdnLcgE%epDbLpdJU#8Md>O=cB`aMPaK;B@qGmPNy%l>?u$r!&m+E^N+$4E|P=<8;_ zeU1{>;^agY<_tY4*1*-XcN^pPG0zacIcAyT+pe@QLm%UFAG`AJHAXwcce=|k10|G0 zGP;wl>_BGcs2gApW6XBfOO*R9G?{D_%V8V@1c8D^r4 z_kk_ywQ05tJ?0)2uc3{WJVQyf{g>C*&I&0z^1G?67>P0B?qSq?OOrs3>wkI2cA4Mv{ba_D_)rTH!3%b~3L-)cCU^_Z<< zjuBnPM$x{&@n4llzn>714^|47Fr7=W(8+_Z;6?qi=9~Q*ld% z$~`ka@yM8<)RjNwk885wBVa277w34MfSYM+2i`uhhO-1Nq}7Zqb!?G?)h6=PwmNtS zGr6aKi?TNz~ zJ;15jaI|_J>hDy&k(1E6jA|j$Fyd|>}AupE|91*tJgsvJIwbrAN#KNl^OlfubKe2^f)dsvicZ$ zI{K*5^P{~6=tq=?(?eTZ&W$kkw9#EJPSl&&S=ZL}SGwsVL}U&s@b$5=mE zPqpaGc^vew{6(2D%cZ_&@PrFgY&6^RJYQsLEIruTRE;$2Z(lwDX^d^@+w<(rmeE4U zN?I8$+M6P$RTs~w78x04kLhe}K|uO`baL+bQJ~T_wxtFbWw?bAr_z zPWpw_-Z7&Ten+j8qZiIs)R%p{^s91fER$59%sDfvXqkCu&Z(LA7M{xLY5aVJuj_1B z%b(56e@7pZ@^88)IL5An2iXBP7o{DXx&{7UVJzC*IczuA7Hcfkbq9RToET$&$|f## zkOipo3fQ-)wNoRfI{C$t|Crbz-dAuhg$6ADz_MzVR#+FfsEJXnZ+9V~c%A7zO~{V_ zoZ4Jp=C)Mp^ka=1Y=k{hXpJ>tBPQ*y-pwaO)~*#?FwbB$H?R*=lhdpq(L>(9X( zGyIZ2=#e^q{@7CX`xrY1CgNQtZALsBIU*kWFd3QsnZ+UB-2u0zw^0t|k@r)Wxn$(Q zn!s?%Yuw9HTap7bsxXr%Xz`;W(b468`& z=&Gsf^2*ndLU|`Iu?8~&d5pF9Dfa=|y7e`uDc2U8kXd9@Mwv^Lo|OdBQ3 zyR~=2uzzo2pGomU2g_ZZ!AvTfJ+sylMX?afP$$1kb#m^;e%GA+C2~n+fJAFBVepd> zCWL=7TFnu&2j*g*1DIe(7FXmaS=0rTb+Mu9BX)^sB3N@pDm1k!-SF?4TUna5_f{6t z#J~OeA7%K5(3ugN93iPnBV@@{Sah4(Ze*@v4YXU~UgR}hS`smZqSl56n?k zlcQ$WueXr<8&|FedL-73>pmB=e_22ulie?RG*RD zLg2ZKAtL|ol~nCri|))m8+=cpu5&}#j}Hd7tw2Wh&)1Fq$ZPrWj?W4{L>63!JZdcn zSSJF}ND#mq-$sM9hACPA-|QdKX`#j7HjmqI4h=-?S;pn+-kx{s-hs6?LWy6A>eu)EQo{b1QpV=peKEr>fTsO?-h z0lQc%2XO(NINH3Ar}V>>mCDt6-GA8S+h?>`E=l84q0(#Q;|T**FSXPyc>n+a literal 8274 zcmeHMYfl?T6uqA-^*^k@l8qG8<_A~`Nhqz95E4lH!HO#52e`ryd6yFB@z>j&GuPvt z*}c0l3ROh05Vq&B^SJlSnRD;{`_D+OWh#BiWGplMO5{j}D7EDj-wXL0^?m$0M(d5d zmDJT9p=E|A=kig0lppYv{>`O_mYz(c71jIpUG#g2_P$(V+$qLN@X7xCHIorOGqkZZ zLXV+b$-vdkT>Angt}2mpS(-C+u_nI;?t{Hs7{7;k2KdY{%L31Kq=6ZF7@s@ZlXtfm z?W8mVZI!`Bx|5DHVZAx(`q;w=vpvJCQ@7vT(!Z?tm!kjOuRwie&HM`1`^&8^`%h+8 zYaGG0Gt5LA9{?-#Yu!Fm^jJ7lT)-O*d4-aC`>FF+bB&ayJTko%A~8hVbBwxJ?boAR zu|_QD97N*yWBK`(Z1^j%m4b^ie4m4xdDr&c{lps1;<=EwW_VMF zH?qIAi9Eeq6KDl;{k7xI7>Priw#1>CCx*Xx6LahYz2CceGCaFPxdoju#_ucqCgOE< z6a417bR_oReUjje9^+JPIa-y6>YcJ0xo;eO2}Hygr6M3JDryebnCZw9Xwc8AGhi{^ zE>QCQFi)L)gS~|4k5Ahc@pY=uQuCYW@BbU(RmXdVPQm<};QkMABqI}ks&e4x6qqCn zt770eBSsT^Q*DsVmA!jTBl$aG0M1Pj)m)(mc{*l$ax=Moh*omFYLwy)5sl7xMcbKUy99CR z8+n2927sTUJ-o&^3^{-Vv8?^5mQm2i%Vt!KNA=krXBXCZ?9moeDjj=7Y zJdE66suIWIMF>X!Kb6JzntUEtRRKJ~pq6XUic zFULM_gWH)OV;+Du3QKKd1gaDQ`_{F#E38#z#n1zvBaHIh1^1Qv!O{xW4QKg=b)J{% z*wuP=4;Bj78GANtc{pC)+!waBtNdn->+cbJB;OkP!A4S@7axk}%2o<%c7b$yK%-lI zk4PTpn?7*tPR_;zlAGVhOc^+ZuAGTQds#rL4RVZzzSB;nX6(a7x2ybl@j33xbu zf0dv-bjpUgPR1&%@r=l~6U>U#%@(s*Joj>Kh45|+-}}){WM9TI6WL#Bh8`H0WsQmU zO$D|O4ReZrGIef6wK{hh+hmhfa`&;S>>|(2j9)xfJg3^XXd|xe6ua`V5AX4pZcqC5 z#CxRsjr$MB{0%oKv7@V|uZt_+#0tfoyuqsTd-fCXae%!HoLZod{M(>#B_8{mSfSzk XSZ}Kkf7Imu%@S`>mi_wJPdV!gv4t;o diff --git a/PoshServiceNow/Public/New-ServiceNowIncident.ps1 b/PoshServiceNow/Public/New-ServiceNowIncident.ps1 index a0f02f5d27c4c25f36030b1778c66bd5e0d86f30..db4d60cf42282706bbeb07b833a39fe540ad42d5 100644 GIT binary patch literal 4600 zcmds5QBT`25PnDEKb%CR6s_e4OhOv!7(-$Ot*{q_keggukHoHQhpLR%YB}@^O>fW81iEkRDT-M;o| zf@Vzbj-$x}W1g-?QV4X0f8v-WIvPOEM8b?ztK*(g1s>jQsgca_+AgQxN$o4Nk)daq zoU-hsF!LAmX!2jo?s_AK-N4)HpAKL$m&!nbI#zt)PO3t@#@Gu7!2K;4y9lpC@S_Ki zfcBUjz=agE*WjD7Om81;PXYX@aNT-wGddf~>R@~tsAj@5t@%vkR3l)fWU+9m-jV5N zZgRVH52AL*P(4|rBn zi|1-_SLNJ#@fM+2!O{kc8Jtm>-@I$^Xm$kA7|l|uhp78T*$lA~vmHXM!lwn>q?pEU zjNGooSpZE7v}VbRrAYa#P|RJ!++g00!A?XrL#|Wozf8~okaNPL1z%ifBXdX{MFXZ` z&h*@{X@=c3YWI*@J4`Ikfl<=c7EU9DmTYsD0rBO;l4C~n(Y~@dYsa3NH!9USX#R*Q zfALiLx=oe8v5XUsrY69Qi!8fTr}@IH`i;7NHSrb)G`r`G^z#EcY9H?ha81p^&DRS^ zB{c!`?AOqprwtP^!W4-Ymr(R^_I^Dfs0BEp?!h)GLm`((vCP9V|8LN!n3H!hz=1q% z0dVr8Pzcl=$h@p0zWD&@x(}c_V;C0|2FiLpfCUjQy4R8c(BZv=ptt4rIZV1P@BwT@ zN0_YJgvaMP%fs04ZkEQ;xw(gO)FZtGYB+`uRm*9w<*4i`sm+XNrs|WtZ;`gW(S6Vx zIk7h14;HjV1F{=Pd1`y_sIAl5VsL>t1)*hcy0ozzgwxfnTe(n@mtbD|i@7x4j{~VV zPp0=Vul8t_-BRvX`BQ%LwBM*WRhk6g){wum$Og5kI_;J=Aa(1W8-@a*C#XDZsBQj@ zaBXY-sW8OWhVB`nx^0bMSeCUFOa+ z#;P=kUb444yF2st&FqYSez#>LJ!wfI9l6A(NVX-GE2+yKo&))T_7*;E0OKIb8B4>~pVXmfh@x!_E z?>f2JBg`{`B<;J2XHu~4gWFyS=8GVkeFs=Uj2&`b&fh_=<;;%!st=`qyEl&Hj7t*s z>)WWa1iGRQVp)|MwAja|7G$@v>vgB&o@?xL(&>}ox9!dzd3^TVc3%X~eg#$8b@nrtacA*td1jmjQDq*!35Fbk z8Bf8z^pcDtB77SFg(I+L@ahpx4$qGri+G>DnHo7u?{0JL9IFXDZ!vnNkCTd-vUs*U zR@V${1$>mVAmg8l6e1N%>Z`jzCVhJZ+%iV?(JDQBOU@liEq1j%M-^oG$kRWoORwga z?iZC7TVPsyzjRj2qUA1RF_MqLaT?86x!1(fK>r4?R&zJ91h+4aK6j_DIvVC!tI5m9 zS{6U$Xxjr<9lLw)zX=Z(NyM6kaN zcN`mDfZHDTUObQ0o^!0G`6de?TVs5bqpt;AG5%xJ7CEHF$PO`!76EPid*+^J=+guv zGN%}snVspQv^k6U_*9>^CaW>{G%Pl0Va??QWTdmJ<#<{LOT{kA=Z&-j%yfYlN@6Qx zerArFXwm3jdof>4X7=yN&-tu5bz>uCQZtX2RsM{XPG*(&vD)&i@>iz`=IV8)tOPK} zJ%WC^vV-v(IDyP|ULz-7d{fv(F5J?woy}e}>krm=X3VKwOT!Czw+|kmeGcRcGF@Z} z#?j#pXIqT-JhBUQ#`;GD28n?R=8My)SVHTmyhU4nL=R(`-)J}l1x(Z-gSC_fHnR74%aS%8)TZSKSd*W?D$jN_t{qV8>3BpvQMM|>*d)|GSeIfvLp;#VSsV<| zqPFHr`uNNYm)_S-Tt!Du-a|2H>E+O2B^QVz^nc$495tv@b8>4a=Ho z&FOgyE#XsyI*_iHjK~OL6~FItRZj2mYVMBZYn58ftc}NH>q+Su!sy{`-RQ`9oyodU zkakyo-=4v)Mg^&MX4jTwWo?hZd_HR%q?YI4Z0X8`J{!zBsOp}2OlReaMyqG?`IYqO z>>GRh5d1KCV-8a6yOAxc1#UTkv?HLSliP=VAM(*|THZ~@o2B2dj=bdRm3EAi^(NW+ zyvJT1C$scTzi_H380joEv(S`Vzq%6GW;(esgo7xC2S;qKLLV?@z^BkY3{G_K!( zMApZzA-xWd@7tL@BUjTFJPqtcyVi5(Jggo_nTP6}fl&+lOnG7F-|* zRw2k7Oo5PdEHf|?q{>jip&c7OcN5T{iYg{DW~6H4AZMk<#ePzzjpE{NAKcgp>oyMM zJqpaeG80~mW#gL<30LR{5Q^?%8URs(I(@m)>0+$?Qw$$j$q6Cu&_te{<6VG9qrCG- zPaxvZHk`xyhUvnvLy3?|VHg({YSk<0)U$eOAc^3}%9>sknp%+rP}SN{u}KTS?<_TC z3sJ+%5)O7;b)aoz&~Q`0YMcB8?P37853cPk8+!?fJ__i=KM_!}(T+vW{{P~?auREY zzZb-Zongv!c73oGC-3G?HP+iU8w}+dgDwdWLm0ktCp?dwKTlhSOMHNkED|m#GBzOg z={uLydUKm>Zr7he_va&$?SEUCY<5>e@e>%!*c-Cp4Xg2CU2_{eieTpq=MwS`7ZgT& z+)*9TkNchC&80%}VidgYa?AxxjPT+cwt8Cql%e;{{~ZDuab8+< z3M^vm|L6K2L@ZuJ3J^1-M&|U0nsixw^y+%CQE{icQr?1Vea;H)G3@$ng$fa`2X}&@ zvKsbm123Yirc~Qzq@U$pH@tCDT-g0iMH=M0yJft-`*$33ZyogrAK4>^e0K1OIfPl> z(6>|j`+Jn{9u7*L!#L&4lIYyJHxip!xJx*7h>7&T-FWU6EHoq35~n*-3EgMAPz`lM!ZUoQ-HN?e<@^7Q)kBL$vtbj7pj?8ObC8$en)CwdOMSZBg`WhAycxvFM& m#bev=L!c6~poMpMgSYI6ZG_6P{}iY2h86FM-=M0lL-`gD@{`E` diff --git a/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 b/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 index 9fc1c11f632c71c9b9501539fdb2df2869bcba25..2b569347a3800af15a7080cf037b1fe2e050f182 100644 GIT binary patch literal 2853 zcmds3QE%He5PmPv|8TGcSivkA?Op;8en#(LqEDsoh0Ar+cq)s9QlCtY<{Z0J^ z#enXQ?I_VA?Rsn81}qN=Bl5_*@4ox))(uZ}AvoONHd>rxM3B7ScA?Hv@wD$jwC|C6-r(3M_OqCA;ym}Ez=@HuGN{l;;uF~ zqedB4jAu*>xtj%AHh6Y_@>J`IIln}0UZ0JYHKxUScO^K-Hkj)I%S?@)e8EbgGk*K< zj&6CnF}d-o6c4PtXmoyPrnDpk?t>Q1v5Us7hVVU8c?TS!xM5|33J9=9Auw7ItP)cp zvyp;YirRpR%3W|8zBMb={{X*ykIjAXQ;W<$V0b0b(5hgi!7VfRF-nH{lrl}k6yT^0 z;Gx%(DePBYrPUbTIHD%UL?uTHVlfqwzG=$xt(;f2-h~HTTr8c(9?1jeq}v~pyUyVu zB*ci-?T@e)vSo*}F*T1s7;2`}mda!dl$);sgr)1$o@_mS(lKsBo{nWcKJLgCt z_jw<_LJg^-xCzk9`t5v~n1DOGVhv&7E`x|81e}OyCD+Qi5pT*vN?o%wUvjU90J2GJ;WI=nQ39E|<7u(6^#mI%z ztv=X9BWY_3v$OVs>;Z?!B9rzt zJNwtSy-;Qlbe(PL9(UVb6FLf#>>k^W=-C;T_9XR@w4i#t)VUN}7|h?NSQ`nL0{ko* zs2Zgq6CjAucHmfxvJ_h*1V@TLgu9xOaD*Bq{`=KFYyihp|{`&a&&(EI*<1ZH0mqxG8 zFL#=Tjv3t9nlvRH&v_~`Grdfwt7Ls1lL)ov!q$DFPWM;h z#OYW&n6$Ibq#KDWKAjWDuEaf`)!Y_RB&L3nIrt{|WDF)M6aC w=pw>WlgcE!8ezcdx-_E!v1{^7s;1P>pHWr)4cCo;@c;k- literal 5690 zcmeHL+iu%N5S`}&{RhGlAO*E#w0#L&L0W{XNN29QbS2@nzz8PNG_K%vomMT%Bu>*Gg)AK zfV-D?yOf^v<*nS}`6=e+c)yb0Ql@L0hnPp% zZP?VuS1Eoend^KcP2A7muOTG8xreOMCtf~%o5QEN_D5LVIjk7M(<69cB`451#vey~ zWKQvJ2;ZkzN$Vq6aN+!FX?}&6|6JJeF*K_;zQx)m(A3BEF}zG9Y}1yxXb=zAh(6Ch@|W~-5tlOPWm?{tm7 zevuiJPQ^seRM2Hy3GigqEdAnely#UuC-x6`vw|i40*~_LabjgB?wc$oBX>mS2H1?LD+AOo1BA;Q`R(2^bsN=1n3Wh9Ju?mqxbl#{m0w3$%ZC z=GUS4|H}Q%8ef<7R{s-vPJ2j>grf~q57rPy+G24ZK|9x9gTci|7uhbFGdh;f%2cjvxVYCa4KWRvkj%q8e`J+2p!&JLyrJnEjne{~*Y9ratD>pFbJ zvODPRGK}9sD>I=74ey-qI&$hzPreI%5L;cXZWbr&3j9tc>|YajdIkNgnRnPHC^q}( zA^EITwOjO`ai()Eb_J=APZv3xL28`i+r1yhZ~NLkBQRbq*Td#ukW7x{2!Ab%e&MiT z$HqeA1#BG^-?bp44|yY8$B4`l*M)ouxmI+-vG3wxj6J8G znjB+1ksmQ*j_VzM8Jz?@D^Df3mnTQZCmiep*}+n(?+CPquj}!tIorqS^zgp0Bs)A^WD_n~C!W zZSz@fRn>ziLo{E)c!&2*c><{^m|rVHyiZHycZ@4X#`W%d#E~oe#_0+rHY)S|{_6s{ zc`6T`?K5De?{sQhGvH$C*2jvPK(;^gVH_D3?kQ&&=exOkuAVe-7c_={cw#{;{w06P zAGjXY+=n(dAu~rm@etlv;ZDyrm|2&Vs_1KS*PZh*x@m#YH>fSgsA@eYr(5(rr95^j z-q&TXRC&?HT0ua$qxDl+V1C^VXkI=2l${CfBNY6^ES)bb31EK zl54HlQ48_OSn{`rxDr!D1}pazxbkNN%2Y=<$x}=pU>4VuVg3`$&fHAh{qvsZY7daD OTm{j13;B$WX4=1UnS9v* diff --git a/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 b/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 index 413d744bb7fd79813ac274e949f6ca200aa98ff6..bce206b1964c283767fccc82d995dd0570508455 100644 GIT binary patch literal 465 zcmb`DF$=;l5QX=G|KSD)JLE@{QbdprP1R9iywX6Ml;Nq?K*^I;|{6;kr6pcLUqZm8%KXPD>7OB r)i5PIqGh9+{zDu#iL?d^^CVzOq*}w-R;Ql znN6vhDcApHI7E*^3wDhTruvF`Fundt%kESRsSwbANsYr4C#{oxgi!^?{()1^oCbRO Vu}AI6ERSzEH=FGq_f7PH^EZmjj1&L> diff --git a/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 b/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 index a212ce57ffececd9c370eb199447577510a72e3f..723ac3c40fa013a186f1c31bfa492122b25d9e8d 100644 GIT binary patch literal 2622 zcmeHJ-%r~x5PlvK|HG+7YS5ZSY;Qi~KHUYn9*5tskO2r^rEfSYpPsHU@GH8s5>V1DjP`gdm5_=>uofgo3p$ZFo&xx@T^0oq-9*v>i?8^ z$~-N9q3l3oPNL#WKxHrotAG*r?pDSuy8l7d0DK16{VfWE84vrhKie+aq@^lk>Pod$_)jRJZONfuRg(8X|IeB16&%*WQK5u zPB)&4e-F0Ne8A9xNkG={?ftCC6=-r)!MrPlIRxbgu{|0DQA-;69+b?OnbLU=s5h?> z6l!@<0MEI=GtF;P{Fd&YGBdHxTHCD;Fze#BUDw}jouGv*sM}#{HT>#mIC5C)5I%-D z3V9%r2$3WWQZ6SiGI96gKGcGYc)n~%g8@+76tx{G@_+Ye=$#5$`TEP%$)33sWKJV| zw2&Mto#9IA#rY9LOdFizEUBFo$o(u9eVQV6j|EL>KlHobo{beeeQHP3?6vY6d=0S0 z?rum1(4AOYn%y+*!uu68fyQgi=~*{rB~PWArPG~mfKy*RH9baQ(9;~ETOgN&L*g2> zs`FRc@lw@cGl%KfQlIKN>-yq&gvPcGa(57&88Wu*XQi;%y9H$cQGJH(hRwrc6ZlyJ zNpbi7>}$n2l`civX0jo*rAs@}Y6hL7#|%q1{ks5PRRu+5EaVClDY|)w7%L&v%pZ@d zX1@#HCG7O!fCrfN literal 5246 zcmeI0TW=#p5QXa%B>qDyu@tXZI|AM!?ZcA2MPe^nJ4h&6fr*`sA+aNSl57_3UkAR^ z<<895?F$J!AgwIVrDwXTy6V)an*Qt06T7sL9a~{T8*>%xtqts)>nqMJ>u{WKJ>;E% zy<+^@y4JH_?Tq`U%qVz%V}ICJ_N5)!K6Cr=Sz+HZYs8(7@2$x*X*l72!dnOYFOVeN zk8H3l5Px$ZCEK7Ji%A@?U6nZ#-vh zV>IJ7Uv`_&C5n53_O3#eN&?lvoe=U-&JsL2_O8XOu1G#*gmSTYT}({ zX3VqiK3wz=3tnRBB42jb^5u`w6XJAVsp^lI@e&p|v)9aj8mmY_b~jh>?i=zy=i_>v zNh~S0SoCCWzSbu1<~+R3v+k?{9a2?);Qj>rC!AAd%IOJ_S;SxRnW}Dp_Xf9oQ=;N? zWRJ)YRo%q%xj5vb=@D5SzsL3wq5i-x+DQ@`;e+zGQV22dfsuuNl0XAzaL01bzh!Yx|od?~n#9rQs zr@M6aEI6LwSv_YJX@M>?p;>+Zgq3wcq4)o3R;Q9{(x3BJJJyi8>=qr{l<_mPDpR{? z_z->9vS$(NV!5gh>Q>L!v>X%r3SJ@S8mp^4X_)nXs+8x}o*}YFzps0*rR`ZyS&l^N7e?bH1`~keiE6b?g%os`vU9ksnGl=XB>Ixrp#UOjAa!;&Z)s_w1O**`~hE ztt`z|G&b|kqLLyTG%)PqK$Mg8jrBmz>Wz zDmsB$txjFviQ?$`K7_hI^{vXQ^6PO`XD=-2sjz=rEOAO9BCDyw@(_0GpF|89jIv2P!~8ApG}e<{mzRduU|BF~p1k|f;~vF?p(^BXX=GoK@ST^4V_h3d(@hu9?-%C9}$r5%PR;H7F+Rln-S0c*Zu z#lK@$EAF-lIWMD?r;MxHYu(z`h?a|=TXXL`VTSKs327~`Ax-mrNS-b8@3z>nll~jz zH7eJV?K>Y{ExWv-{U~LIs>KC%Xn#=OXr3Lr>V3BwbFx#cu|p7PvT+QMqQ}gvW<#}UtRrWmZiJ6iXKYH zzsbwYo0rMw$DN+E&{RR0a#lMU%d^|JxzIEADV7UPUvvaI=s|DV))v^ZEtRUEKdRHP zSLZicBcg8)x&t~T-i$HeyU?qKa;yttcy)FAgRhlgGVb1kai9y$wbzQSv)l}uF}x!q zPd+`JTTUs=;@-nCU@cY4E#pe(o-R@N815boN@T|Ex#iSmUo|r9Hg-;@+{`sG4};dX zyVgi&yx5SQ@P>i5g!@2!T7q?#Ug=p^?l0a)Iw9(n>QUUUJYuwj$SEu`=7m*QpNc!c g{@?iRij~?_~{j5z1U&H_|EdT%j From 825296a36ab1927c061fbba6577f539004eaa5d2 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 10 Aug 2017 10:41:35 -0500 Subject: [PATCH 045/348] Lost Update-ServiceNowIncident in merge. Adding it back. --- .../Public/Update-ServiceNowIncident.ps1 | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 ServiceNow/Public/Update-ServiceNowIncident.ps1 diff --git a/ServiceNow/Public/Update-ServiceNowIncident.ps1 b/ServiceNow/Public/Update-ServiceNowIncident.ps1 new file mode 100644 index 0000000..ecbcc1a --- /dev/null +++ b/ServiceNow/Public/Update-ServiceNowIncident.ps1 @@ -0,0 +1,45 @@ +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 + } +} \ No newline at end of file From e4bed3304b724da762e5604470f2922b0ba05ab3 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 10 Aug 2017 10:42:11 -0500 Subject: [PATCH 046/348] Deleting old psm1 files that came back after merge --- PSServiceNow-Incidents.psm1 | 277 --------------------------------- PSServiceNow-Tables.psm1 | 296 ------------------------------------ 2 files changed, 573 deletions(-) delete mode 100644 PSServiceNow-Incidents.psm1 delete mode 100644 PSServiceNow-Tables.psm1 diff --git a/PSServiceNow-Incidents.psm1 b/PSServiceNow-Incidents.psm1 deleted file mode 100644 index 8315202..0000000 --- a/PSServiceNow-Incidents.psm1 +++ /dev/null @@ -1,277 +0,0 @@ -<# -.Synopsis - Returns incidents from the connected ServiceNow instance based (optionally based on criteria) -.NOTES - You must have invoked Set-ServiceNowAuth prior to executing this cmdlet -.EXAMPLE - Return the incident whose number is exactly INC0010683 - Get-ServiceNowIncident -MatchExact @{number='INC0010683'} -.EXAMPLE - Return all incidents where the short description contains the word 'user' - Get-ServiceNowIncident -MatchContains @{short_description='user'} -#> - -function Get-ServiceNowIncident{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='opened_at', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # 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) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - - # Return that result! - return $result -} - -<# -.EXAMPLE - New-ServiceNowIncident -ShortDescription "Testing with Pester" ` - -Description "Long description" -AssignmentGroup "e9e9a2406f4c35001855fa0dba3ee4f3" ` - -Category "Internal" -SubCategory "Task" ` - -Comment "Comment" -ConfigurationItem "bee8e0ed6f8475001855fa0dba3ee4ea" ` - -Caller "7a4b573a6f3725001855fa0dba3ee485" ` -#> -function New-ServiceNowIncident{ - Param( - - # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] - [string]$Caller, - - # Short description of the incident - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] - [string]$ShortDescription, - - # Long description of the incident - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Description, - - # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$AssignmentGroup, - - # Comment to include in the ticket - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Comment, - - # Category of the incident (e.g. 'Network') - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Category, - - # Subcategory of the incident (e.g. 'Network') - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Subcategory, - - # sys_id of the configuration item of the incident - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$ConfigurationItem, - - # custom fields as hashtable - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$CustomFields, - - # 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 - ) - - - $Values = @{ - 'caller_id' = $Caller - 'short_description' = $ShortDescription - 'description' = $Description - 'assignment_group' = $AssignmentGroup - 'comments' = $Comment - 'category' = $Category - 'subcategory' = $Subcategory - 'cmdb_ci' = $ConfigurationItem - } - - if($CustomFields) - { - $Values += $CustomFields - } - - if ($Connection -ne $null) - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values - } - -} - - -<# -.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 deleted file mode 100644 index 7df4b37..0000000 --- a/PSServiceNow-Tables.psm1 +++ /dev/null @@ -1,296 +0,0 @@ -function Get-ServiceNowTable -{ - [OutputType([Array])] - Param - ( - # Name of the table we're querying (e.g. incidents) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Table, - - # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Query, - - # Maximum number of records to return - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Whether or not to show human readable display values instead of machine values - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', - - # 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 - ) - - #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" - } - - # Populate the query - $Body = @{'sysparm_limit'=$Limit;'sysparm_display_value'=$DisplayValues} - if($Query){ - $Body.sysparm_query = $Query - } - - # Fire and return - $Uri = $ServiceNowURL + "/table/$Table" - - return (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result -} - -function New-ServiceNowTableEntry{ - Param - ( - # Name of the table we're inserting into (e.g. incidents) - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Table, - - # Hashtable of values to use as the record's properties - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$Values, - - # 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 - ) - - - #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" - return (Invoke-RestMethod -Uri $uri -Method Post -Credential $ServiceNowCredential -Body $utf8Bytes -ContentType "application/json" -UseBasicParsing).result -} - -<# -.COMMENT - Untested -#> -function Remove-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 - ) - - #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" - } - - # 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 From e4fbd18684911044476f3de5456ea2d45771bb7f Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 10 Aug 2017 10:43:30 -0500 Subject: [PATCH 047/348] Renamed module from PoshServiceNow to ServiceNow. Build v 0.1.36 --- .gitignore | 2 +- Readme.md | 14 +- .../Public/Get-ServiceNowChangeRequest.ps1 | 158 ++++++------ .../Get-ServiceNowConfigurationItem.ps1 | 164 ++++++------- .../Public/Get-ServiceNowIncident.ps1 | 178 +++++++------- .../Public/Get-ServiceNowTable.ps1 | 164 ++++++------- .../Public/Get-ServiceNowUser.ps1 | 174 ++++++------- .../Public/Get-ServiceNowUserGroup.ps1 | 180 +++++++------- .../Public/New-ServiceNowIncident.ps1 | 230 +++++++++--------- .../Public/New-ServiceNowQuery.ps1 | 90 +++---- .../Public/New-ServiceNowTableEntry.ps1 | 138 +++++------ .../Public/Remove-ServiceNowAuth.ps1 | 36 +-- .../Public/Remove-ServiceNowTableEntry.ps1 | 124 +++++----- .../Public/Set-ServiceNowAuth.ps1 | 26 +- .../Public/Test-ServiceNowAuthIsSet.ps1 | 14 +- .../ServiceNow-Automation.json | 64 ++--- .../ServiceNow.format.ps1xml | 4 +- .../ServiceNow.psd1 | 10 +- .../ServiceNow.psm1 | 0 ...viceNow.Tests.ps1 => ServiceNow.Tests.ps1} | 46 ++-- 20 files changed, 916 insertions(+), 900 deletions(-) rename {PoshServiceNow => ServiceNow}/Public/Get-ServiceNowChangeRequest.ps1 (96%) rename {PoshServiceNow => ServiceNow}/Public/Get-ServiceNowConfigurationItem.ps1 (95%) rename {PoshServiceNow => ServiceNow}/Public/Get-ServiceNowIncident.ps1 (95%) rename {PoshServiceNow => ServiceNow}/Public/Get-ServiceNowTable.ps1 (97%) rename {PoshServiceNow => ServiceNow}/Public/Get-ServiceNowUser.ps1 (97%) rename {PoshServiceNow => ServiceNow}/Public/Get-ServiceNowUserGroup.ps1 (97%) rename {PoshServiceNow => ServiceNow}/Public/New-ServiceNowIncident.ps1 (97%) rename {PoshServiceNow => ServiceNow}/Public/New-ServiceNowQuery.ps1 (96%) rename {PoshServiceNow => ServiceNow}/Public/New-ServiceNowTableEntry.ps1 (97%) rename {PoshServiceNow => ServiceNow}/Public/Remove-ServiceNowAuth.ps1 (96%) rename {PoshServiceNow => ServiceNow}/Public/Remove-ServiceNowTableEntry.ps1 (97%) rename {PoshServiceNow => ServiceNow}/Public/Set-ServiceNowAuth.ps1 (96%) rename {PoshServiceNow => ServiceNow}/Public/Test-ServiceNowAuthIsSet.ps1 (95%) rename PoshServiceNow/PoshServiceNow-Automation.json => ServiceNow/ServiceNow-Automation.json (90%) rename PoshServiceNow/PoshServiceNow.format.ps1xml => ServiceNow/ServiceNow.format.ps1xml (95%) rename PoshServiceNow/PoshServiceNow.psd1 => ServiceNow/ServiceNow.psd1 (93%) rename PoshServiceNow/PoshServiceNow.psm1 => ServiceNow/ServiceNow.psm1 (100%) rename Tests/{PoshServiceNow.Tests.ps1 => ServiceNow.Tests.ps1} (70%) diff --git a/.gitignore b/.gitignore index 6316a65..0ec1138 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ ServiceNow-Module.Pester.Defaults.json *.zip -PoshServiceNow.Pester.Defaults.json +ServiceNow.Pester.Defaults.json diff --git a/Readme.md b/Readme.md index 1e0b000..c60439c 100644 --- a/Readme.md +++ b/Readme.md @@ -1,5 +1,5 @@ -# PoshServiceNow -[![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-74%25-orange.svg) +# ServiceNow +[![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-73%25-orange.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. @@ -8,19 +8,19 @@ Requires PowerShell 3.0 or above as this is when `Invoke-RestMethod` was introdu ## Usage Download the [latest release](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: -`Import-Module PoshServiceNow` -Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module PoshServiceNow`. +`Import-Module ServiceNow` +Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module ServiceNow`. ### Example - Retrieving an Incident Containing the Word 'PowerShell' ``` -Import-Module PoshServiceNow +Import-Module ServiceNow Set-ServiceNowAuth Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} ``` ### Example - Retrieving an Incident Containing the Word 'PowerShell' While Passing Authentication ``` -Import-Module PoshServiceNow +Import-Module ServiceNow Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} -ServiceNowCredential $PSCredential -ServiceNowURL $ServiceNowURL ``` @@ -31,7 +31,7 @@ Update-ServiceNowIncident -SysID $Incident.Sys_ID -Values @{comments='Updated vi ``` ### Azure Connection Object (Automation Integration Module Support) -The module can use the `Connection` parameter in conjunction with the included `PoshServiceNow-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). +The module can use the `Connection` parameter in conjunction with the included `ServiceNow-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). The `Connection` parameter accepts a hashtable object that requires a username, password, and ServiceNowURL. diff --git a/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 similarity index 96% rename from PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 rename to ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index d03332b..48129aa 100644 --- a/PoshServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -1,79 +1,79 @@ -function Get-ServiceNowChangeRequest { - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='opened_at', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, - - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection - ) - - $private:Query = New-ServiceNowQuery -OrderBy $private:OrderBy -OrderDirection $private:OrderDirection -MatchExact $private:MatchExact -MatchContains $private:MatchContains - - - if ($Connection -ne $null) { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues - } - - # Add the custom type to the change request to enable a view - $private:result | ForEach-Object {$_.psobject.TypeNames.Insert(0, "PoshServiceNow.ChangeRequest")} - return $private:result -} +function Get-ServiceNowChangeRequest { + param( + # Machine name of the field to order by + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$OrderBy='opened_at', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection='Desc', + + # Maximum number of records to return + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [int]$Limit=10, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchExact=@{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchContains=@{}, + + # Whether or not to show human readable display values instead of machine values + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("true","false", "all")] + [string]$DisplayValues='true', + + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [PSCredential] + $ServiceNowCredential, + + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [string] + $ServiceNowURL, + + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [Hashtable] + $Connection + ) + + $private:Query = New-ServiceNowQuery -OrderBy $private:OrderBy -OrderDirection $private:OrderDirection -MatchExact $private:MatchExact -MatchContains $private:MatchContains + + + if ($Connection -ne $null) { + $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues -Connection $Connection + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { + $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + } + else { + $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues + } + + # Add the custom type to the change request to enable a view + $private:result | ForEach-Object {$_.psobject.TypeNames.Insert(0, "ServiceNow.ChangeRequest")} + return $private:result +} diff --git a/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 similarity index 95% rename from PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 rename to ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index a4941f1..ad3d7e3 100644 --- a/PoshServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -1,82 +1,82 @@ -function Get-ServiceNowConfigurationItem { - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, - - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - - # Set the default property set for the table view - $DefaultProperties = @('name', 'category', 'subcategory') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(‘DefaultDisplayPropertySet’,[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} +function Get-ServiceNowConfigurationItem { + param( + # Machine name of the field to order by + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$OrderBy='name', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection='Desc', + + # Maximum number of records to return + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [int]$Limit=10, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchExact=@{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchContains=@{}, + + # Whether or not to show human readable display values instead of machine values + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("true","false", "all")] + [string]$DisplayValues='true', + + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [PSCredential] + $ServiceNowCredential, + + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [string] + $ServiceNowURL, + + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [Hashtable] + $Connection + ) + + $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains + + if ($Connection -ne $null) { + $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { + $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + } + else { + $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues + } + + + # Set the default property set for the table view + $DefaultProperties = @('name', 'category', 'subcategory') + $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) + $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) + $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers + return $result +} diff --git a/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 similarity index 95% rename from PoshServiceNow/Public/Get-ServiceNowIncident.ps1 rename to ServiceNow/Public/Get-ServiceNowIncident.ps1 index 11d35ac..2c1f771 100644 --- a/PoshServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -1,89 +1,89 @@ -function Get-ServiceNowIncident{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='opened_at', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # 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) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - - # Return that result! - return $result -} +function Get-ServiceNowIncident{ + param( + # Machine name of the field to order by + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$OrderBy='opened_at', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection='Desc', + + # Maximum number of records to return + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [int]$Limit=10, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchExact=@{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchContains=@{}, + + # Whether or not to show human readable display values instead of machine values + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("true","false", "all")] + [string]$DisplayValues='true', + + # 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 + ) + + $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains + + if ($Connection -ne $null) + { + $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) + { + $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + } + else + { + $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues + } + + # 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) + $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) + $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers + + # Return that result! + return $result +} diff --git a/PoshServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 similarity index 97% rename from PoshServiceNow/Public/Get-ServiceNowTable.ps1 rename to ServiceNow/Public/Get-ServiceNowTable.ps1 index b78eba0..107db39 100644 --- a/PoshServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -1,82 +1,82 @@ -function Get-ServiceNowTable -{ - [OutputType([Array])] - Param - ( - # Name of the table we're querying (e.g. incidents) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Table, - - # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Query, - - # Maximum number of records to return - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Whether or not to show human readable display values instead of machine values - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', - - # 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 - ) - - #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" - } - - # Populate the query - $Body = @{'sysparm_limit'=$Limit;'sysparm_display_value'=$DisplayValues} - if($Query){ - $Body.sysparm_query = $Query - } - - # Fire and return - $Uri = $ServiceNowURL + "/table/$Table" - - return (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result -} +function Get-ServiceNowTable +{ + [OutputType([Array])] + Param + ( + # Name of the table we're querying (e.g. incidents) + [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Table, + + # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) + [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Query, + + # Maximum number of records to return + [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [int]$Limit=10, + + # Whether or not to show human readable display values instead of machine values + [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("true","false", "all")] + [string]$DisplayValues='false', + + # 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 + ) + + #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" + } + + # Populate the query + $Body = @{'sysparm_limit'=$Limit;'sysparm_display_value'=$DisplayValues} + if($Query){ + $Body.sysparm_query = $Query + } + + # Fire and return + $Uri = $ServiceNowURL + "/table/$Table" + + return (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result +} diff --git a/PoshServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 similarity index 97% rename from PoshServiceNow/Public/Get-ServiceNowUser.ps1 rename to ServiceNow/Public/Get-ServiceNowUser.ps1 index d5065dd..b076557 100644 --- a/PoshServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -1,87 +1,87 @@ -function Get-ServiceNowUser{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # Set the default property set for the table view - $DefaultProperties = @('name', 'email', 'sys_id') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} +function Get-ServiceNowUser{ + param( + # Machine name of the field to order by + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$OrderBy='name', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection='Desc', + + # Maximum number of records to return + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [int]$Limit=10, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchExact=@{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchContains=@{}, + + # Whether or not to show human readable display values instead of machine values + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("true","false", "all")] + [string]$DisplayValues='true', + + # 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 + ) + + $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains + + if ($Connection -ne $null) + { + $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) + { + $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + } + else + { + $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues + } + + # Set the default property set for the table view + $DefaultProperties = @('name', 'email', 'sys_id') + $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) + $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) + $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers + return $result +} diff --git a/PoshServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 similarity index 97% rename from PoshServiceNow/Public/Get-ServiceNowUserGroup.ps1 rename to ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index a9e1392..be0412a 100644 --- a/PoshServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -1,90 +1,90 @@ -function Get-ServiceNowUserGroup{ - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, - - # Whether or not to show human readable display values instead of machine values - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', - - # 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 - ) - - - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # Set the default property set for the table view - $DefaultProperties = @('name', 'email', 'sys_id') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result -} +function Get-ServiceNowUserGroup{ + param( + # Machine name of the field to order by + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$OrderBy='name', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection='Desc', + + # Maximum number of records to return + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [int]$Limit=10, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchExact=@{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$MatchContains=@{}, + + # Whether or not to show human readable display values instead of machine values + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateSet("true","false", "all")] + [string]$DisplayValues='true', + + # 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 + ) + + + $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains + + + if ($Connection -ne $null) + { + $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) + { + + $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + } + else + { + $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues + } + + # Set the default property set for the table view + $DefaultProperties = @('name', 'email', 'sys_id') + $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) + $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) + $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers + return $result +} diff --git a/PoshServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 similarity index 97% rename from PoshServiceNow/Public/New-ServiceNowIncident.ps1 rename to ServiceNow/Public/New-ServiceNowIncident.ps1 index db4d60c..35513d6 100644 --- a/PoshServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -1,115 +1,115 @@ -function New-ServiceNowIncident{ - Param( - - # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] - [string]$Caller, - - # Short description of the incident - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] - [string]$ShortDescription, - - # Long description of the incident - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Description, - - # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$AssignmentGroup, - - # Comment to include in the ticket - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Comment, - - # Category of the incident (e.g. 'Network') - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Category, - - # Subcategory of the incident (e.g. 'Network') - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Subcategory, - - # sys_id of the configuration item of the incident - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$ConfigurationItem, - - # custom fields as hashtable - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$CustomFields, - - # 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 - ) - - - $Values = @{ - 'caller_id' = $Caller - 'short_description' = $ShortDescription - 'description' = $Description - 'assignment_group' = $AssignmentGroup - 'comments' = $Comment - 'category' = $Category - 'subcategory' = $Subcategory - 'cmdb_ci' = $ConfigurationItem - } - - if($CustomFields) - { - $Values += $CustomFields - } - - if ($Connection -ne $null) - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values -Connection $Connection - } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL - } - else - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values - } - -} +function New-ServiceNowIncident{ + Param( + + # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) + [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] + [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] + [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] + [string]$Caller, + + # Short description of the incident + [parameter(mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] + [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] + [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] + [string]$ShortDescription, + + # Long description of the incident + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Description, + + # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$AssignmentGroup, + + # Comment to include in the ticket + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Comment, + + # Category of the incident (e.g. 'Network') + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Category, + + # Subcategory of the incident (e.g. 'Network') + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Subcategory, + + # sys_id of the configuration item of the incident + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$ConfigurationItem, + + # custom fields as hashtable + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$CustomFields, + + # 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 + ) + + + $Values = @{ + 'caller_id' = $Caller + 'short_description' = $ShortDescription + 'description' = $Description + 'assignment_group' = $AssignmentGroup + 'comments' = $Comment + 'category' = $Category + 'subcategory' = $Subcategory + 'cmdb_ci' = $ConfigurationItem + } + + if($CustomFields) + { + $Values += $CustomFields + } + + if ($Connection -ne $null) + { + New-ServiceNowTableEntry -Table 'incident' -Values $Values -Connection $Connection + } + elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) + { + New-ServiceNowTableEntry -Table 'incident' -Values $Values -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + } + else + { + New-ServiceNowTableEntry -Table 'incident' -Values $Values + } + +} diff --git a/PoshServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 similarity index 96% rename from PoshServiceNow/Public/New-ServiceNowQuery.ps1 rename to ServiceNow/Public/New-ServiceNowQuery.ps1 index 5a1902c..66e4ca8 100644 --- a/PoshServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -1,45 +1,45 @@ -function New-ServiceNowQuery{ - - param( - # Machine name of the field to order by - [parameter(mandatory=$false)] - [string]$OrderBy='opened_at', - - # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [hashtable]$MatchExact, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [hashtable]$MatchContains - ) - # Start the query off with a order direction - $Query = ''; - if($OrderDirection -eq 'Asc'){ - $Query += 'ORDERBY' - }else{ - $Query += 'ORDERBYDESC' - } - $Query +="$OrderBy" - - # Build the exact matches into the query - if($MatchExact){ - foreach($Field in $MatchExact.keys){ - $Query += "^$Field="+$MatchExact.$Field - } - } - - # Add the values which given fields should contain - if($MatchContains){ - foreach($Field in $MatchContains.keys){ - $Query += "^$($Field)LIKE"+$MatchContains.$Field - } - } - - return $Query -} +function New-ServiceNowQuery{ + + param( + # Machine name of the field to order by + [parameter(mandatory=$false)] + [string]$OrderBy='opened_at', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory=$false)] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection='Desc', + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory=$false)] + [hashtable]$MatchExact, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory=$false)] + [hashtable]$MatchContains + ) + # Start the query off with a order direction + $Query = ''; + if($OrderDirection -eq 'Asc'){ + $Query += 'ORDERBY' + }else{ + $Query += 'ORDERBYDESC' + } + $Query +="$OrderBy" + + # Build the exact matches into the query + if($MatchExact){ + foreach($Field in $MatchExact.keys){ + $Query += "^$Field="+$MatchExact.$Field + } + } + + # Add the values which given fields should contain + if($MatchContains){ + foreach($Field in $MatchContains.keys){ + $Query += "^$($Field)LIKE"+$MatchContains.$Field + } + } + + return $Query +} diff --git a/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 b/ServiceNow/Public/New-ServiceNowTableEntry.ps1 similarity index 97% rename from PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 rename to ServiceNow/Public/New-ServiceNowTableEntry.ps1 index 2b56934..1cc721d 100644 --- a/PoshServiceNow/Public/New-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/New-ServiceNowTableEntry.ps1 @@ -1,69 +1,69 @@ -function New-ServiceNowTableEntry{ - Param - ( - # Name of the table we're inserting into (e.g. incidents) - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Table, - - # Hashtable of values to use as the record's properties - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$Values, - - # 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 - ) - - - #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" - return (Invoke-RestMethod -Uri $uri -Method Post -Credential $ServiceNowCredential -Body $utf8Bytes -ContentType "application/json" -UseBasicParsing).result -} +function New-ServiceNowTableEntry{ + Param + ( + # Name of the table we're inserting into (e.g. incidents) + [parameter(mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Table, + + # Hashtable of values to use as the record's properties + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$Values, + + # 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 + ) + + + #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" + return (Invoke-RestMethod -Uri $uri -Method Post -Credential $ServiceNowCredential -Body $utf8Bytes -ContentType "application/json" -UseBasicParsing).result +} diff --git a/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 b/ServiceNow/Public/Remove-ServiceNowAuth.ps1 similarity index 96% rename from PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 rename to ServiceNow/Public/Remove-ServiceNowAuth.ps1 index bce206b..35ecbac 100644 --- a/PoshServiceNow/Public/Remove-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAuth.ps1 @@ -1,18 +1,18 @@ -function Remove-ServiceNowAuth{ - - If (-not (Test-ServiceNowAuthIsSet)) { - Return $true - } - - Try { - Remove-Variable -Name ServiceNowURL -Scope Global -ErrorAction Stop - Remove-Variable -Name ServiceNowRESTURL -Scope Global -ErrorAction Stop - Remove-Variable -Name ServiceNowCredentials -Scope Global -ErrorAction Stop - } - Catch { - Write-Error $_ - Return $false - } - - Return $true -} +function Remove-ServiceNowAuth{ + + If (-not (Test-ServiceNowAuthIsSet)) { + Return $true + } + + Try { + Remove-Variable -Name ServiceNowURL -Scope Global -ErrorAction Stop + Remove-Variable -Name ServiceNowRESTURL -Scope Global -ErrorAction Stop + Remove-Variable -Name ServiceNowCredentials -Scope Global -ErrorAction Stop + } + Catch { + Write-Error $_ + Return $false + } + + Return $true +} diff --git a/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 similarity index 97% rename from PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 rename to ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 index 723ac3c..573bbcf 100644 --- a/PoshServiceNow/Public/Remove-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 @@ -1,62 +1,62 @@ -function Remove-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 - ) - - #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" - } - - # Fire and return - $Uri = $ServiceNowURL + "/table/$Table/$SysID" - return (Invoke-RestMethod -Uri $uri -Method Delete -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result -} +function Remove-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 + ) + + #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" + } + + # Fire and return + $Uri = $ServiceNowURL + "/table/$Table/$SysID" + return (Invoke-RestMethod -Uri $uri -Method Delete -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result +} diff --git a/PoshServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 similarity index 96% rename from PoshServiceNow/Public/Set-ServiceNowAuth.ps1 rename to ServiceNow/Public/Set-ServiceNowAuth.ps1 index 823ff6f..08f3a74 100644 --- a/PoshServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -1,13 +1,13 @@ -function Set-ServiceNowAuth{ - param( - [parameter(mandatory=$true)] - [string]$url, - - [parameter(mandatory=$true)] - [System.Management.Automation.PSCredential]$Credentials - ) - $Global:ServiceNowURL = 'https://' + $url - $Global:ServiceNowRESTURL = $ServiceNowURL + '/api/now/v1' - $Global:ServiceNowCredentials = $credentials - return $true; -} +function Set-ServiceNowAuth{ + param( + [parameter(mandatory=$true)] + [string]$url, + + [parameter(mandatory=$true)] + [System.Management.Automation.PSCredential]$Credentials + ) + $Global:ServiceNowURL = 'https://' + $url + $Global:ServiceNowRESTURL = $ServiceNowURL + '/api/now/v1' + $Global:ServiceNowCredentials = $credentials + return $true; +} diff --git a/PoshServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 b/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 similarity index 95% rename from PoshServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 rename to ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 index 7cbb054..c388819 100644 --- a/PoshServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 +++ b/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 @@ -1,7 +1,7 @@ -function Test-ServiceNowAuthIsSet{ - if($Global:ServiceNowCredentials){ - return $true; - }else{ - return $false; - } -} +function Test-ServiceNowAuthIsSet{ + if($Global:ServiceNowCredentials){ + return $true; + }else{ + return $false; + } +} diff --git a/PoshServiceNow/PoshServiceNow-Automation.json b/ServiceNow/ServiceNow-Automation.json similarity index 90% rename from PoshServiceNow/PoshServiceNow-Automation.json rename to ServiceNow/ServiceNow-Automation.json index 3e3ea22..ceabcdf 100644 --- a/PoshServiceNow/PoshServiceNow-Automation.json +++ b/ServiceNow/ServiceNow-Automation.json @@ -1,32 +1,32 @@ -{ - "ConnectionFields": [ - { - "IsEncrypted": false, - "IsOptional": false, - "Name": "Username", - "TypeName": "System.String" - }, - { - "IsEncrypted": true, - "IsOptional": false, - "Name": "Password", - "TypeName": "System.String" - }, - { - "IsEncrypted": false, - "IsOptional": false, - "Name": "ServiceNowUri", - "TypeName": "System.String" - }, - { - "IsEncrypted": false, - "IsOptional": true, - "Name": "APIVersion", - "TypeName": "System.String" - } - - ], - - "ConnectionTypeName": "ServiceNow", - "IntegrationModuleName": "PoshServiceNow" -} +{ + "ConnectionFields": [ + { + "IsEncrypted": false, + "IsOptional": false, + "Name": "Username", + "TypeName": "System.String" + }, + { + "IsEncrypted": true, + "IsOptional": false, + "Name": "Password", + "TypeName": "System.String" + }, + { + "IsEncrypted": false, + "IsOptional": false, + "Name": "ServiceNowUri", + "TypeName": "System.String" + }, + { + "IsEncrypted": false, + "IsOptional": true, + "Name": "APIVersion", + "TypeName": "System.String" + } + + ], + + "ConnectionTypeName": "ServiceNow", + "IntegrationModuleName": "ServiceNow" +} diff --git a/PoshServiceNow/PoshServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml similarity index 95% rename from PoshServiceNow/PoshServiceNow.format.ps1xml rename to ServiceNow/ServiceNow.format.ps1xml index 4af5be2..aed0d22 100644 --- a/PoshServiceNow/PoshServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -2,9 +2,9 @@ - PoshServiceNow.ChangeRequest + ServiceNow.ChangeRequest - PoshServiceNow.ChangeRequest + ServiceNow.ChangeRequest diff --git a/PoshServiceNow/PoshServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 similarity index 93% rename from PoshServiceNow/PoshServiceNow.psd1 rename to ServiceNow/ServiceNow.psd1 index 682111d..4148f64 100644 --- a/PoshServiceNow/PoshServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -1,5 +1,5 @@ # -# Module manifest for module 'PoshServiceNow' +# Module manifest for module 'ServiceNow' # # Generated by: Sam Martin # @@ -9,10 +9,10 @@ @{ # Script module or binary module file associated with this manifest. -RootModule = 'PoshServiceNow.psm1' +RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.35' +ModuleVersion = '0.1.36' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -60,13 +60,13 @@ Description = 'This module provides cmdlets allowing you to retrieve information # TypesToProcess = @() # Format files (.ps1xml) to be loaded when importing this module -FormatsToProcess = @('PoshServiceNow.format.ps1xml') +FormatsToProcess = @('ServiceNow.format.ps1xml') # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowIncident') # List of all modules packaged with this module # ModuleList = @() diff --git a/PoshServiceNow/PoshServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 similarity index 100% rename from PoshServiceNow/PoshServiceNow.psm1 rename to ServiceNow/ServiceNow.psm1 diff --git a/Tests/PoshServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 similarity index 70% rename from Tests/PoshServiceNow.Tests.ps1 rename to Tests/ServiceNow.Tests.ps1 index 5ff3788..03b88e1 100644 --- a/Tests/PoshServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -49,13 +49,21 @@ Describe "ServiceNow-Module" { } It "New-ServiceNowIncident (and by extension New-ServiceNowTableEntry) works" { - $TestTicket = New-ServiceNowIncident -ShortDescription "Testing 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 with Pester" + $ShortDescription = "Testing Ticket Creation with Pester" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = "Long description" + AssignmentGroup = $Defaults.TestUserGroup + Comment = "Comment" + Category = $Defaults.TestCategory + SubCategory = $Defaults.TestSubcategory + ConfigurationItem = $Defaults.TestConfigurationItem + + } + $TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should be $ShortDescription } It "Get-ServiceNowTable works" { @@ -68,20 +76,28 @@ Describe "ServiceNow-Module" { (Get-ServiceNowIncident).Count -gt 0 | Should Match $true } - 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 ` + It "Update-ServiceNowIncident works" { + $ShortDescription = "Testing Ticket Update with Pester" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = "Long description" + AssignmentGroup = $Defaults.TestUserGroup + Comment = "Comment" + Category = $Defaults.TestCategory + SubCategory = $Defaults.TestSubcategory + ConfigurationItem = $Defaults.TestConfigurationItem + + } + $TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat - $TestTicket.short_description | Should be "Testing Ticket Update with Pester" + $TestTicket.short_description | Should be $ShortDescription $Values = @{ 'short_description' = 'Ticket Updated with Pester' 'description' = 'Even Longer Description' - } + } Update-ServiceNowIncident -SysId $TestTicket.sys_id -Values $Values From 0318e43734ff0b721d89c126e733f0ddcb3cfa1a Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 29 Aug 2017 16:22:40 -0500 Subject: [PATCH 048/348] Reformatted function with splatting, updated/expanded format.ps1xml in all Get functions --- .../Public/Get-ServiceNowChangeRequest.ps1 | 40 ++- .../Get-ServiceNowConfigurationItem.ps1 | 41 ++- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 43 +-- ServiceNow/Public/Get-ServiceNowTable.ps1 | 29 +- ServiceNow/Public/Get-ServiceNowUser.ps1 | 43 +-- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 42 +-- ServiceNow/ServiceNow.format.ps1xml | 253 +++++++++++++----- 7 files changed, 342 insertions(+), 149 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 48129aa..28329f8 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -60,20 +60,36 @@ function Get-ServiceNowChangeRequest { $Connection ) - $private:Query = New-ServiceNowQuery -OrderBy $private:OrderBy -OrderDirection $private:OrderDirection -MatchExact $private:MatchExact -MatchContains $private:MatchContains + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + MatchExact = $MatchExact + OrderDirection = $OrderDirection + MatchContains = $MatchContains + } + $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - if ($Connection -ne $null) { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues -Connection $Connection + # Table Splat + $getServiceNowTableSplat = @{ + Table = 'change_request' + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + + # Update the Table Splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $getServiceNowTableSplat.Add('Connection',$Connection) } - else { - $private:result = Get-ServiceNowTable -Table 'change_request' -Query $private:Query -Limit $private:Limit -DisplayValues $private:DisplayValues + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + { + $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } - # Add the custom type to the change request to enable a view - $private:result | ForEach-Object {$_.psobject.TypeNames.Insert(0, "ServiceNow.ChangeRequest")} - return $private:result -} + # Perform query and return each object in the format.ps1xml format + $Result = Get-ServiceNowTable @getServiceNowTableSplat + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ChangeRequest")} + $Result +} \ No newline at end of file diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index ad3d7e3..780645a 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -60,23 +60,36 @@ function Get-ServiceNowConfigurationItem { $Connection ) - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + MatchExact = $MatchExact + OrderDirection = $OrderDirection + MatchContains = $MatchContains + } + $Query = New-ServiceNowQuery @newServiceNowQuerySplat - if ($Connection -ne $null) { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection + # Table Splat + $getServiceNowTableSplat = @{ + Table = 'cmdb_ci' + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + + # Update the Table Splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $getServiceNowTableSplat.Add('Connection',$Connection) } - else { - $result = Get-ServiceNowTable -Table 'cmdb_ci' -Query $Query -Limit $Limit -DisplayValues $DisplayValues + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + { + $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } - - # Set the default property set for the table view - $DefaultProperties = @('name', 'category', 'subcategory') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result + # Perform query and return each object in the format.ps1xml format + $Result = Get-ServiceNowTable @getServiceNowTableSplat + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ConfigurationItem")} + $Result } diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 2c1f771..1823a27 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -63,27 +63,36 @@ function Get-ServiceNowIncident{ $Connection ) - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + OrderDirection = $OrderDirection + MatchExact = $MatchExact + MatchContains = $MatchContains + } + $Query = New-ServiceNowQuery @newServiceNowQuerySplat + + # Table Splat + $getServiceNowTableSplat = @{ + Table = 'incident' + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues + } - if ($Connection -ne $null) + # Update the splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection + $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } - else - { - $result = Get-ServiceNowTable -Table 'incident' -Query $Query -Limit $Limit -DisplayValues $DisplayValues - } - - # 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) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - # Return that result! - return $result + # Perform query and return each object in the format.ps1xml format + $Result = Get-ServiceNowTable @getServiceNowTableSplat + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.Incident")} + $Result } diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 107db39..f2c49b3 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -40,22 +40,21 @@ function Get-ServiceNowTable [string] $ServiceNowURL, - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection ) - #Get credential and ServiceNow REST URL - if ($Connection -ne $null) + # Get credential and ServiceNow REST URL + if ($null -ne $Connection) { $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) + elseif ($null -ne $ServiceNowCredential -and $null -ne $ServiceNowURL) { $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' } @@ -64,7 +63,7 @@ function Get-ServiceNowTable $ServiceNowCredential = $Global:ServiceNowCredentials $ServiceNowURL = $global:ServiceNowRESTURL } - else + 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" } @@ -75,8 +74,20 @@ function Get-ServiceNowTable $Body.sysparm_query = $Query } - # Fire and return + # Perform table query and capture results $Uri = $ServiceNowURL + "/table/$Table" + $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result + + # Convert specific fields to DateTime format + $ConvertToDateField = @('closed_at','expected_start','follow_up','opened_at','sys_created_on','sys_updated_on','work_end','work_start') + ForEach ($SNResult in $Result) { + ForEach ($Property in $ConvertToDateField) { + If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { + $SNResult.$Property = [datetime]$SNResult.$Property + } + } + } - return (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result -} + # Return the results + $Result +} \ No newline at end of file diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index b076557..68113cd 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -63,25 +63,36 @@ function Get-ServiceNowUser{ $Connection ) - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + OrderDirection = $OrderDirection + MatchExact = $MatchExact + MatchContains = $MatchContains } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + $Query = New-ServiceNowQuery @newServiceNowQuerySplat + + # Table Splat + $getServiceNowTableSplat = @{ + Table = 'sys_user' + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues + } + + # Update the splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $getServiceNowTableSplat.Add('Connection',$Connection) } - else + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $result = Get-ServiceNowTable -Table 'sys_user' -Query $Query -Limit $Limit -DisplayValues $DisplayValues + $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } - # Set the default property set for the table view - $DefaultProperties = @('name', 'email', 'sys_id') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result + # Perform query and return each object in the format.ps1xml format + $Result = Get-ServiceNowTable @getServiceNowTableSplat + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.UserAndUserGroup")} + $Result } diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index be0412a..24f7171 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -63,28 +63,36 @@ function Get-ServiceNowUserGroup{ $Connection ) + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + OrderDirection = $OrderDirection + MatchExact = $MatchExact + MatchContains = $MatchContains + } + $Query = New-ServiceNowQuery @newServiceNowQuerySplat - $Query = New-ServiceNowQuery -OrderBy $OrderBy -OrderDirection $OrderDirection -MatchExact $MatchExact -MatchContains $MatchContains - - - if ($Connection -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -Connection $Connection + # Table Splat + $getServiceNowTableSplat = @{ + Table = 'sys_user_group' + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + # Update the splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $getServiceNowTableSplat.Add('Connection',$Connection) } - else + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $result = Get-ServiceNowTable -Table 'sys_user_group' -Query $Query -Limit $Limit -DisplayValues $DisplayValues + $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } - # Set the default property set for the table view - $DefaultProperties = @('name', 'email', 'sys_id') - $DefaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',[string[]]$DefaultProperties) - $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($DefaultDisplayPropertySet) - $Result | Add-Member MemberSet PSStandardMembers $PSStandardMembers - return $result + # Perform query and return each object in the format.ps1xml format + $Result = Get-ServiceNowTable @getServiceNowTableSplat + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.UserAndUserGroup")} + $Result } diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index aed0d22..06d8572 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -1,67 +1,192 @@ - - - ServiceNow.ChangeRequest - - ServiceNow.ChangeRequest - - - - - 20 - - - - 20 - - - - 20 - - - 20 - - - - 30 - - - 20 - - - - - - - number - - - short_description - - - state - - - - $_.assigned_to.display_value - - - - approval - - - - $_.cmdb_ci.display_value - - - - opened_at - - - - - - - + + + ServiceNow.ChangeRequest + + ServiceNow.ChangeRequest + + + + + + 10 + + + + 25 + + + + 8 + + + + 15 + + + + 10 + + + + 20 + + + + 21 + + + + + + + number + + + short_description + + + state + + + + $_.assigned_to.display_value + + + + approval + + + + $_.cmdb_ci.display_value + + + + opened_at + + + + + + + + ServiceNow.ConfigurationItem + + ServiceNow.ConfigurationItem + + + + + + 60 + + + + 20 + + + + 20 + + + + + + + name + + + category + + + subcategory + + + + + + + + ServiceNow.Incident + + ServiceNow.Incident + + + + + + 10 + + + + 20 + + + + 15 + + + + 60 + + + + + + + number + + + opened_at + + + state + + + short_description + + + + + + + + ServiceNow.UserAndUserGroup + + ServiceNow.UserAndUserGroup + + + + + + 40 + + + + 40 + + + + 40 + + + + + + + name + + + email + + + sys_id + + + + + + + \ No newline at end of file From 708521eeb38eb0e24157cd6f42b292f34ba92a67 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 29 Aug 2017 16:49:13 -0500 Subject: [PATCH 049/348] Set Table param mandatory, cleaned up all param settings --- ServiceNow/Public/Get-ServiceNowTable.ps1 | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index f2c49b3..7c14c6d 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -4,37 +4,39 @@ function Get-ServiceNowTable Param ( # Name of the table we're querying (e.g. incidents) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] + [parameter(Mandatory)] + [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] + [ValidateNotNullOrEmpty()] [string]$Table, # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$Query, # Maximum number of records to return - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, # Whether or not to show human readable display values instead of machine values - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] + [ValidateSet("true","false","all")] [string]$DisplayValues='false', # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName='SpecifyConnectionFields')] [ValidateNotNullOrEmpty()] [PSCredential] $ServiceNowCredential, - # The URL for the ServiceNow instance being used + # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] From e37cdf201bf5a4f086020ceb510771acbe54ff67 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 30 Aug 2017 11:21:14 -0500 Subject: [PATCH 050/348] Lost Update-ServiceNowTableEntry in merge. Adding it back. --- .../Public/Update-ServiceNowTableEntry.ps1 | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 ServiceNow/Public/Update-ServiceNowTableEntry.ps1 diff --git a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 new file mode 100644 index 0000000..c38e433 --- /dev/null +++ b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 @@ -0,0 +1,71 @@ +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 From 22eedc45e1d59aec64b3a3cefe3df320d2fb2191 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 30 Aug 2017 11:22:05 -0500 Subject: [PATCH 051/348] Updated function formatting. Added splatting. --- .../Public/Update-ServiceNowIncident.ps1 | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowIncident.ps1 b/ServiceNow/Public/Update-ServiceNowIncident.ps1 index ecbcc1a..9ed4f43 100644 --- a/ServiceNow/Public/Update-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Update-ServiceNowIncident.ps1 @@ -14,32 +14,36 @@ function Update-ServiceNowIncident { # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [PSCredential]$ServiceNowCredential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [string]$ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [Hashtable]$Connection ) - if ($Connection -ne $null) - { - Update-ServiceNowTableEntry -Table 'incident' -Values $Values -Connection $Connection -SysId $SysId + $updateServiceNowTableEntrySplat = @{ + SysId = $SysId + Table = 'incident' + Values = $Values } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - Update-ServiceNowTableEntry -Table 'incident' -Values $Values -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL -SysId $SysId + + # Update the splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $updateServiceNowTableEntrySplat.Add('Connection',$Connection) } - else + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - Update-ServiceNowTableEntry -Table 'incident' -Values $Values -SysId $SysId - } -} \ No newline at end of file + $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) + $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) + } + + Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat +} + From e00acb040563310d124b5d16a1d0ec069c536330 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 30 Aug 2017 12:17:14 -0500 Subject: [PATCH 052/348] Lost Update-ServiceNowChangeRequest in merge. Adding it back. --- .../Public/Update-ServiceNowChangeRequest.ps1 | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 diff --git a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 new file mode 100644 index 0000000..ef733b2 --- /dev/null +++ b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 @@ -0,0 +1,53 @@ +<# +.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')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [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 + ) + + $updateServiceNowTableEntrySplat = @{ + SysId = $SysId + Table = 'change_request' + Values = $Values + } + + # Update the splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $updateServiceNowTableEntrySplat.Add('Connection',$Connection) + } + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + { + $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) + $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) + } + + Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat +} \ No newline at end of file From bc2eb2cc346065affa61a8f4ca81bb3ac1347552 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 30 Aug 2017 18:05:46 -0500 Subject: [PATCH 053/348] Cleaned up New-ServiceNowIncident. Added error checking for duplicate incident fields --- ServiceNow/Public/New-ServiceNowIncident.ps1 | 99 +++++++++++++------- 1 file changed, 63 insertions(+), 36 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 35513d6..1e6a3aa 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -2,16 +2,17 @@ function New-ServiceNowIncident{ Param( # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] + [parameter(Mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] [string]$Caller, # Short description of the incident - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] + [parameter(Mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] [string]$ShortDescription, # Long description of the incident @@ -66,50 +67,76 @@ function New-ServiceNowIncident{ # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [PSCredential]$ServiceNowCredential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [string]$ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [Hashtable]$Connection ) - - $Values = @{ - 'caller_id' = $Caller - 'short_description' = $ShortDescription - 'description' = $Description - 'assignment_group' = $AssignmentGroup - 'comments' = $Comment - 'category' = $Category - 'subcategory' = $Subcategory - 'cmdb_ci' = $ConfigurationItem + # Create a hash table of any defined parameters (not CustomFields) that have values + $DefinedIncidentParameters = @('AssignmentGroup','Caller','Category','Comment','ConfigurationItem','Description','ShortDescription','Subcategory') + $TableEntryValues = @{} + ForEach ($Parameter in $DefinedIncidentParameters) { + If ($null -ne $PSBoundParameters.$Parameter) { + # Turn the defined parameter name into the ServiceNow attribute name + $KeyToAdd = Switch ($Parameter) { + AssignmentGroup {'assignment_group'} + Caller {'caller_id'} + Category {'category'} + Comment {'comments'} + ConfigurationItem {'cmdb_ci'} + Description {'description'} + ShortDescription {'short_description'} + Subcategory {'subcategory'} + } + $TableEntryValues.Add($KeyToAdd,$PSBoundParameters.$Parameter) + } } - if($CustomFields) - { - $Values += $CustomFields + # Add CustomFields hash pairs to the Table Entry Values hash table + If ($null -ne $PSBoundParameters.CustomFields) { + $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { + If (($TableEntryValues.ContainsKey($Key) -eq $False)) { + # Add the unique entry to the table entry values hash table + $TableEntryValues.Add($Key,$CustomFields[$Key]) + } + Else { + # Capture the duplicate key name + $Key + } + } + } + + # Throw an error if duplicate fields were provided + If ($null -ne $DuplicateTableEntryValues) { + $DuplicateKeyList = $DuplicateTableEntryValues -join "," + Throw "Ticket fields may only be used once: $DuplicateKeyList" } - if ($Connection -ne $null) - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values -Connection $Connection + # Table Entry Splat + $newServiceNowTableEntrySplat = @{ + Table = 'incident' + Values = $TableEntryValues } - elseif ($ServiceNowCredential -ne $null -and $ServiceNowURL -ne $null) - { - New-ServiceNowTableEntry -Table 'incident' -Values $Values -ServiceNowCredential $ServiceNowCredential -ServiceNowURL $ServiceNowURL + + # Update the splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $newServiceNowTableEntrySplat.Add('Connection',$Connection) } - else + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - New-ServiceNowTableEntry -Table 'incident' -Values $Values - } - + $newServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) + $newServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) + } + + # Create the table entry + New-ServiceNowTableEntry @newServiceNowTableEntrySplat } From de3639ca5230ec53f0305ae96b28b933dce704ef Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 14 Sep 2017 12:06:08 -0500 Subject: [PATCH 054/348] Build v0.1.37 --- ServiceNow/ServiceNow.psd1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 4148f64..fe5c673 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.36' +ModuleVersion = '0.1.37' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowIncident') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From 203e12d4e2c279aad5c9c97a5938c82b56ae90cf Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 4 Dec 2017 16:06:28 -0600 Subject: [PATCH 055/348] ReadMe Update --- Readme.md | 58 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/Readme.md b/Readme.md index c60439c..8e905e1 100644 --- a/Readme.md +++ b/Readme.md @@ -1,41 +1,71 @@ -# ServiceNow -[![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-73%25-orange.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. +# ServiceNow + +[![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-73%25-orange.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. +## Version 2 Overview + +The module has been renamed from PSServiceNow to ServiceNow for version 2. This change moves us away from the reserved "PS" prefix. In addition to the name change the following high level changes have been made: + +Back End: + +* The module structure has been updated to individual files for each function. +* The build process has been migrated from MAKE to psake with support of the BuildHelpers module. +* Pester testing has been expanded to cover more scenarios. +* Improved code formatting, removed aliases, fixed file encoding. + +The gains are marginal in some aspects, but may allow for better management in the future including setting the stage for the ability to use AppVeyor & PSDeploy. + +Front End: + +* The following fields are now returned in the DateTime format instead of string: 'closed_at','expected_start','follow_up','opened_at','sys_created_on','sys_updated_on','work_end','work_start' +* The formatting of returned data has been updated across all the `Get` functions except `Get-ServiceNowTable`. This means you'll see a handful of default properties returned and can use `Format-List` or `Select-Object` to view all other properties associated with the object. + +Thse changes should improve your ability to filter on the right, especially by DateTime, as well as return more information in general. + ## Requirements + Requires PowerShell 3.0 or above as this is when `Invoke-RestMethod` was introduced. ## Usage -Download the [latest release](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: -`Import-Module ServiceNow` + +Download the [latest release](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: +`Import-Module ServiceNow` Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module ServiceNow`. ### Example - Retrieving an Incident Containing the Word 'PowerShell' -``` + +```PowerShell Import-Module ServiceNow -Set-ServiceNowAuth -Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} +Set-ServiceNowAuth +Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} ``` ### Example - Retrieving an Incident Containing the Word 'PowerShell' While Passing Authentication -``` + +```PowerShell Import-Module ServiceNow Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} -ServiceNowCredential $PSCredential -ServiceNowURL $ServiceNowURL ``` ### Example - Update a Ticket -``` + +```PowerShell $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 `ServiceNow-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). + +The module can use the `Connection` parameter in conjunction with the included `ServiceNow-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). The `Connection` parameter accepts a hashtable object that requires a username, password, and ServiceNowURL. -## Cmdlets +## Cmdlets + * Get-ServiceNowChangeRequest * Get-ServiceNowConfigurationItem * Get-ServiceNowIncident @@ -54,11 +84,13 @@ The `Connection` parameter accepts a hashtable object that requires a username, * Update-ServiceNowTableEntry ## Tests + This module comes with [Pester](https://github.com/pester/Pester/) tests for unit testing. ## Scope & Contributing + This module has been created as an abstraction layer to suit my immediate requirements. Contributions are gratefully received however, so please feel free to submit a pull request with additional features or amendments. ## Author -Author:: Sam Martin () +Author:: Sam Martin () \ No newline at end of file From b3cf92f7a49c2f7a1fa22c6ec314cbf86b8d0a1f Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 9 Jan 2018 17:03:33 -0600 Subject: [PATCH 056/348] Updated ReadMe to reference v1. Added example to help with issue #2 --- Readme.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Readme.md b/Readme.md index 8e905e1..6f58eda 100644 --- a/Readme.md +++ b/Readme.md @@ -6,9 +6,11 @@ This PowerShell module provides a series of cmdlets for interacting with the [Se **IMPORTANT:** Neither this module nor its creator are in any way affiliated with ServiceNow. -## Version 2 Overview +## Version 1 -The module has been renamed from PSServiceNow to ServiceNow for version 2. This change moves us away from the reserved "PS" prefix. In addition to the name change the following high level changes have been made: +The module has been renamed from PSServiceNow to ServiceNow for version 1. This change moves us away from the reserved "PS" prefix. Since the name change is a major change for the user base and the project was never incremented to v1 we've taken the opportunity to label it such. + +In addition to the name change the following high level changes have been made: Back End: @@ -17,14 +19,14 @@ Back End: * Pester testing has been expanded to cover more scenarios. * Improved code formatting, removed aliases, fixed file encoding. -The gains are marginal in some aspects, but may allow for better management in the future including setting the stage for the ability to use AppVeyor & PSDeploy. +The gains are marginal in some aspects, but intended to allow for better management in the future. Front End: * The following fields are now returned in the DateTime format instead of string: 'closed_at','expected_start','follow_up','opened_at','sys_created_on','sys_updated_on','work_end','work_start' * The formatting of returned data has been updated across all the `Get` functions except `Get-ServiceNowTable`. This means you'll see a handful of default properties returned and can use `Format-List` or `Select-Object` to view all other properties associated with the object. -Thse changes should improve your ability to filter on the right, especially by DateTime, as well as return more information in general. +These changes should improve your ability to filter on the right, especially by DateTime, as well as return more information in general. ## Requirements @@ -36,6 +38,14 @@ Download the [latest release](https://github.com/Sam-Martin/servicenow-powershel `Import-Module ServiceNow` Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module ServiceNow`. +### Example - Using Set-ServiceNowAuth + +```PowerShell +Set-ServiceNowAuth -url InstanceName -Credentials (Get-Credential) +``` + +The URL should be the instance name portion of the FQDN for your instance. For if you browse to `myinstance.service-now.com` the URL required for the module is `myinstance`. + ### Example - Retrieving an Incident Containing the Word 'PowerShell' ```PowerShell @@ -93,4 +103,4 @@ This module has been created as an abstraction layer to suit my immediate requir ## Author -Author:: Sam Martin () \ No newline at end of file +Author:: Sam Martin () From daa10c84ba92fdaa4b40666be25741651f6783d7 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 10 Jan 2018 11:30:45 -0600 Subject: [PATCH 057/348] Updated gitignore to ignore any Pester.Defaults.json file --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 0ec1138..3031fa8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -ServiceNow-Module.Pester.Defaults.json +*.Pester.Defaults.json *.zip -ServiceNow.Pester.Defaults.json From d8f35623fd1c360fb50de6077c8085f0d3332e64 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 10 Jan 2018 11:31:30 -0600 Subject: [PATCH 058/348] Updated psd1 to v1.0.0 --- ServiceNow/ServiceNow.psd1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index fe5c673..93c4a36 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '0.1.37' +ModuleVersion = '1.0.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -98,4 +98,4 @@ PrivateData = @{ # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' -} \ No newline at end of file +} From c96c8fbb21940785408edc2f8b260016fc48dfb2 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 10 Jan 2018 13:16:28 -0600 Subject: [PATCH 059/348] Fixed some test file logic & updated Pester tests to use new syntax --- Tests/ServiceNow.Tests.ps1 | 59 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index 03b88e1..c438e45 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -5,7 +5,8 @@ $DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.jso # Load defaults from file (merging into $global:ServiceNowPesterTestDefaults) if(Test-Path $DefaultsFile){ - $defaults = if($global:ServiceNowPesterTestDefaults){$global:ServiceNowPesterTestDefaults}else{@{}}; + $defaults = @{} + # Add properties to the defaults hash (Get-Content $DefaultsFile | Out-String | ConvertFrom-Json).psobject.properties | ForEach-Object { $defaults."$($_.Name)" = $_.Value } @@ -15,8 +16,6 @@ if(Test-Path $DefaultsFile){ $global:ServiceNowPesterTestDefaults = $defaults }else{ - Write-Error "$DefaultsFile does not exist. Created example file. Please populate with your values" - # Write example file @{ ServiceNowURL = 'testingurl.service-now.com' @@ -24,7 +23,8 @@ if(Test-Path $DefaultsFile){ TestUserGroup = 'e9e9a2406f4c35001855fa0dba3ee4f3' TestUser = "7a4b573a6f3725001855fa0dba3ee485" } | ConvertTo-Json | Set-Content $DefaultsFile - return + Write-Error "$DefaultsFile does not exist. Created example file. Please populate with your values" + Return } # Load the module (unload it first in case we've made changes since loading it previously) @@ -33,19 +33,19 @@ Import-Module (Join-Path $moduleRoot "$moduleName.psd1") -Force Describe "ServiceNow-Module" { If (Test-ServiceNowAuthisSet) { - Remove-ServiceNowAuth + Remove-ServiceNowAuth | Should -Be $True } It "Test-ServiceNowAuthIsSet not set" { - Test-ServiceNowAuthIsSet | Should be $false + Test-ServiceNowAuthIsSet | Should -Be $false } It "Set-ServiceNowAuth works" { - Set-ServiceNowAuth -url $defaults.ServiceNowURL -Credentials $defaults.Creds | Should be $true + Set-ServiceNowAuth -url $defaults.ServiceNowURL -Credentials $defaults.Creds | Should -Be $true } It "Test-ServiceNowAuthIsSet set" { - Test-ServiceNowAuthIsSet | Should be $true + Test-ServiceNowAuthIsSet | Should -Be $true } It "New-ServiceNowIncident (and by extension New-ServiceNowTableEntry) works" { @@ -58,22 +58,21 @@ Describe "ServiceNow-Module" { Comment = "Comment" Category = $Defaults.TestCategory SubCategory = $Defaults.TestSubcategory - ConfigurationItem = $Defaults.TestConfigurationItem - - } + ConfigurationItem = $Defaults.TestConfigurationIte + } $TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat - $TestTicket.short_description | Should be $ShortDescription + $TestTicket.short_description | Should -Be $ShortDescription } It "Get-ServiceNowTable works" { # There should be one or more incidents returned - (Get-ServiceNowTable -Table 'incident' -Query 'ORDERBYDESCopened_at').Count -gt 0 | Should Match $true + (Get-ServiceNowTable -Table 'incident' -Query 'ORDERBYDESCopened_at').Count -gt 0 | Should -Match $true } It "Get-ServiceNowIncident works" { # There should be one or more incidents returned - (Get-ServiceNowIncident).Count -gt 0 | Should Match $true + (Get-ServiceNowIncident).Count -gt 0 | Should -Match $true } It "Update-ServiceNowIncident works" { @@ -88,44 +87,44 @@ Describe "ServiceNow-Module" { SubCategory = $Defaults.TestSubcategory ConfigurationItem = $Defaults.TestConfigurationItem - } + } $TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat - - $TestTicket.short_description | Should be $ShortDescription - - $Values = + + $TestTicket.short_description | Should -Be $ShortDescription + + $Values = @{ 'short_description' = 'Ticket Updated with Pester' - 'description' = 'Even Longer Description' + '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" + $TestTicket.short_description | Should -Be "Ticket Updated with Pester" + $TestTicket.description | Should -Be "Even Longer Description" } - It "Get-ServiceNowUserGroup works" { + It "Get-ServiceNowUserGroup works" { # There should be one or more user groups returned - (Get-ServiceNowUserGroup).Count -gt 0 | Should Match $true + (Get-ServiceNowUserGroup).Count -gt 0 | Should -Match $true } It "Get-ServiceNowUser works" { # There should be one or more user groups returned - (Get-ServiceNowUser).Count -gt 0 | Should Match $true + (Get-ServiceNowUser).Count -gt 0 | Should -Match $true } It "Get-ServiceNowConfigurationItem works" { # There should be one or more configuration items returned - (Get-ServiceNowConfigurationItem).Count -gt 0 | Should Match $true + (Get-ServiceNowConfigurationItem).Count -gt 0 | Should -Match $true } - It "Get-ServiceNowChangeRequest works" { - (Get-ServiceNowChangeRequest).Count -gt 0 | Should Match $true + It "Get-ServiceNowChangeRequest works" { + (Get-ServiceNowChangeRequest).Count -gt 0 | Should -Match $true } It "Remove-ServiceNowAuth works" { Remove-ServiceNowAuth | Should be $true } -} \ No newline at end of file +} From c45d24a26d6762ab7d1c3ba698f57abd66773cb0 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 10 Jan 2018 13:20:02 -0600 Subject: [PATCH 060/348] Update ReadMe - fixed Set-ServiceNowAuth example --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 6f58eda..6daa751 100644 --- a/Readme.md +++ b/Readme.md @@ -41,10 +41,10 @@ Once you've done this, all the cmdlets will be at your disposal, you can see a f ### Example - Using Set-ServiceNowAuth ```PowerShell -Set-ServiceNowAuth -url InstanceName -Credentials (Get-Credential) +Set-ServiceNowAuth -url InstanceName.service-now.com -Credentials (Get-Credential) ``` -The URL should be the instance name portion of the FQDN for your instance. For if you browse to `myinstance.service-now.com` the URL required for the module is `myinstance`. +The URL should be the instance name portion of the FQDN for your instance. For if you browse to `https://myinstance.service-now.com` the URL required for the module is `myinstance.service-now.com`. ### Example - Retrieving an Incident Containing the Word 'PowerShell' From 5912af3cb918fdc6ff77449fef5cdfeb70eabf4e Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Thu, 11 Jan 2018 13:37:26 +0000 Subject: [PATCH 061/348] Update Get-ServiceNowTable.ps1 Added correct string to datatime casting using the local computer's culture settings. --- ServiceNow/Public/Get-ServiceNowTable.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 7c14c6d..a3dae7c 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -85,11 +85,16 @@ function Get-ServiceNowTable ForEach ($SNResult in $Result) { ForEach ($Property in $ConvertToDateField) { If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { - $SNResult.$Property = [datetime]$SNResult.$Property + # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now + $CultureDateTimeFormat = (Get-Culture).DateTimeFormat + $DateFormat = $CultureDateTimeFormat.ShortDatePattern + $TimeFormat = $CultureDateTimeFormat.LongTimePattern + $DateTimeFormat = "$DateFormat $TimeFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) } } } # Return the results $Result -} \ No newline at end of file +} From e84c5f8ceb7cd6b4648212aa39f5c817ed363d50 Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 12 Jan 2018 09:46:57 +0000 Subject: [PATCH 062/348] Update Get-ServiceNowTable.ps1 Updated with Rick's additional changes. --- ServiceNow/Public/Get-ServiceNowTable.ps1 | 91 ++++++++++++----------- 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index a3dae7c..0b3c524 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -1,78 +1,73 @@ -function Get-ServiceNowTable -{ +function Get-ServiceNowTable { [OutputType([Array])] Param ( # Name of the table we're querying (e.g. incidents) [parameter(Mandatory)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] [ValidateNotNullOrEmpty()] [string]$Table, # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] [string]$Query, # Maximum number of records to return - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [int]$Limit = 10, # Whether or not to show human readable display values instead of machine values - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false","all")] - [string]$DisplayValues='false', + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [ValidateSet("true", "false", "all")] + [string]$DisplayValues = 'false', # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields')] + [Parameter(ParameterSetName = 'SpecifyConnectionFields')] [ValidateNotNullOrEmpty()] [PSCredential] $ServiceNowCredential, # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [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)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection ) # Get credential and ServiceNow REST URL - if ($null -ne $Connection) - { + if ($null -ne $Connection) { $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 ($null -ne $ServiceNowCredential -and $null -ne $ServiceNowURL) - { + elseif ($null -ne $ServiceNowCredential -and $null -ne $ServiceNowURL) { $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' } - elseif((Test-ServiceNowAuthIsSet)) - { + elseif ((Test-ServiceNowAuthIsSet)) { $ServiceNowCredential = $Global:ServiceNowCredentials $ServiceNowURL = $global:ServiceNowRESTURL } - else - { + 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" } # Populate the query - $Body = @{'sysparm_limit'=$Limit;'sysparm_display_value'=$DisplayValues} - if($Query){ + $Body = @{'sysparm_limit' = $Limit; 'sysparm_display_value' = $DisplayValues} + if ($Query) { $Body.sysparm_query = $Query } @@ -81,18 +76,30 @@ function Get-ServiceNowTable $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result # Convert specific fields to DateTime format - $ConvertToDateField = @('closed_at','expected_start','follow_up','opened_at','sys_created_on','sys_updated_on','work_end','work_start') - ForEach ($SNResult in $Result) { - ForEach ($Property in $ConvertToDateField) { - If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { - # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now - $CultureDateTimeFormat = (Get-Culture).DateTimeFormat - $DateFormat = $CultureDateTimeFormat.ShortDatePattern - $TimeFormat = $CultureDateTimeFormat.LongTimePattern - $DateTimeFormat = "$DateFormat $TimeFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } - } + $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') + ForEach ($SNResult in $Result) { + ForEach ($Property in $ConvertToDateField) { + If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { + Try { + # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now + $CultureDateTimeFormat = (Get-Culture).DateTimeFormat + $DateFormat = $CultureDateTimeFormat.ShortDatePattern + $TimeFormat = $CultureDateTimeFormat.LongTimePattern + $DateTimeFormat = "$DateFormat $TimeFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } + Catch { + Try { + # Universal Format + $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } + Catch { + # If the local culture and universal formats both fail keep the property as a string (Do nothing) + } + } + } + } } # Return the results From 1b3ca3df0b5bb5f4cf15a8db17e5391a2983544b Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 16 Jan 2018 10:08:34 -0600 Subject: [PATCH 063/348] v1.0.1 - For PR #22 and Issue #25 --- Readme.md | 2 +- ServiceNow/Public/Get-ServiceNowTable.ps1 | 21 ++++++++++----------- ServiceNow/ServiceNow.psd1 | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Readme.md b/Readme.md index 6daa751..56912ce 100644 --- a/Readme.md +++ b/Readme.md @@ -23,7 +23,7 @@ The gains are marginal in some aspects, but intended to allow for better managem Front End: -* The following fields are now returned in the DateTime format instead of string: 'closed_at','expected_start','follow_up','opened_at','sys_created_on','sys_updated_on','work_end','work_start' +* The following fields are now returned in the DateTime format instead of string: 'closed_at','expected_start','follow_up','opened_at','sys_created_on','sys_updated_on','work_end','work_start' [v1.0.1 Update: This process now attempts to format the property as DateTime based off your local culture settings, a universal `yyyy-MM-dd HH:mm:ss` format, and finally leaves the property as a string if those two convert attempts fail]. * The formatting of returned data has been updated across all the `Get` functions except `Get-ServiceNowTable`. This means you'll see a handful of default properties returned and can use `Format-List` or `Select-Object` to view all other properties associated with the object. These changes should improve your ability to filter on the right, especially by DateTime, as well as return more information in general. diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 0b3c524..d80f929 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -1,7 +1,6 @@ function Get-ServiceNowTable { [OutputType([Array])] - Param - ( + Param ( # Name of the table we're querying (e.g. incidents) [parameter(Mandatory)] [parameter(ParameterSetName = 'SpecifyConnectionFields')] @@ -9,7 +8,7 @@ function Get-ServiceNowTable { [parameter(ParameterSetName = 'SetGlobalAuth')] [ValidateNotNullOrEmpty()] [string]$Table, - + # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) [parameter(ParameterSetName = 'SpecifyConnectionFields')] [parameter(ParameterSetName = 'UseConnectionObject')] @@ -28,21 +27,21 @@ function Get-ServiceNowTable { [parameter(ParameterSetName = 'SetGlobalAuth')] [ValidateSet("true", "false", "all")] [string]$DisplayValues = 'false', - - # Credential used to authenticate to ServiceNow + + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName = 'SpecifyConnectionFields')] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, # The URL for the ServiceNow instance being used [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -53,14 +52,14 @@ function Get-ServiceNowTable { $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 ($null -ne $ServiceNowCredential -and $null -ne $ServiceNowURL) { $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" } @@ -70,7 +69,7 @@ function Get-ServiceNowTable { if ($Query) { $Body.sysparm_query = $Query } - + # Perform table query and capture results $Uri = $ServiceNowURL + "/table/$Table" $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 93c4a36..d36b962 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -1,4 +1,4 @@ -# +# # Module manifest for module 'ServiceNow' # # Generated by: Sam Martin @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.0.0' +ModuleVersion = '1.0.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From ac3e56f058b4bf38aa729ff70152a4a9ad0f93f8 Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 19 Jan 2018 22:32:35 +0000 Subject: [PATCH 064/348] Create Get-ServiceNowRequest --- ServiceNow/Public/Get-ServiceNowRequest | 93 +++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 ServiceNow/Public/Get-ServiceNowRequest diff --git a/ServiceNow/Public/Get-ServiceNowRequest b/ServiceNow/Public/Get-ServiceNowRequest new file mode 100644 index 0000000..d59520d --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowRequest @@ -0,0 +1,93 @@ +function Get-ServiceNowRequest { + param( + # Machine name of the field to order by + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string]$OrderBy = 'opened_at', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection = 'Desc', + + # Maximum number of records to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [int]$Limit = 10, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [hashtable]$MatchExact = @{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [hashtable]$MatchContains = @{}, + + # Whether or not to show human readable display values instead of machine values + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [ValidateSet("true", "false", "all")] + [string]$DisplayValues = 'true', + + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [PSCredential] + $ServiceNowCredential, + + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [string] + $ServiceNowURL, + + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [Hashtable] + $Connection + ) + + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + MatchExact = $MatchExact + OrderDirection = $OrderDirection + MatchContains = $MatchContains + } + $Query = New-ServiceNowQuery @newServiceNowQuerySplat + + # Table Splat + $getServiceNowTableSplat = @{ + Table = 'sc_request' + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues + } + + # Update the Table Splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) { + $getServiceNowTableSplat.Add('Connection', $Connection) + } + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) + } + + # Perform query and return each object in the format.ps1xml format + $Result = Get-ServiceNowTable @getServiceNowTableSplat + $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0, "ServiceNow.Request")} + $Result +} From f6da6f2c8b7b2cbec3deaa52dd7fccf27070deba Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 19 Jan 2018 23:41:03 +0000 Subject: [PATCH 065/348] Update ServiceNow.format.ps1xml Supersedes my previous pull request. This removes an unnecessary table column for requests. --- ServiceNow/ServiceNow.format.ps1xml | 62 ++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index 06d8572..5f0c18c 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -70,6 +70,66 @@ + + ServiceNow.Request + + ServiceNow.Request + + + + + + 10 + + + + 25 + + + + 8 + + + + 15 + + + + 10 + + + + 21 + + + + + + + number + + + short_description + + + state + + + + $_.assigned_to.display_value + + + + approval + + + opened_at + + + + + + ServiceNow.ConfigurationItem @@ -189,4 +249,4 @@ - \ No newline at end of file + From 227095de958bf458206328969fa2552e12ffe0fa Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 26 Jan 2018 01:14:39 +0000 Subject: [PATCH 066/348] Update Set-ServiceNowAuth.ps1 Fixes #2. --- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index 08f3a74..a5c0f2c 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -1,13 +1,22 @@ -function Set-ServiceNowAuth{ +function Set-ServiceNowAuth { + [CmdletBinding()] param( - [parameter(mandatory=$true)] + [parameter(mandatory = $true)] + [ValidateNotNullOrEmpty()] + [ValidateScript( { if ($_ -notlike 'https://*') { + $true + } + else { + Throw "Please exclude https:// from your URL parameter: $_ " + } })] [string]$url, - [parameter(mandatory=$true)] + [parameter(mandatory = $true)] + [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCredential]$Credentials ) $Global:ServiceNowURL = 'https://' + $url $Global:ServiceNowRESTURL = $ServiceNowURL + '/api/now/v1' $Global:ServiceNowCredentials = $credentials - return $true; + return $true } From db6047d84e8003fc2512c37c716de5820f56367e Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 26 Jan 2018 19:46:15 +0000 Subject: [PATCH 067/348] Update Readme.md --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 56912ce..5a966a7 100644 --- a/Readme.md +++ b/Readme.md @@ -44,7 +44,7 @@ Once you've done this, all the cmdlets will be at your disposal, you can see a f Set-ServiceNowAuth -url InstanceName.service-now.com -Credentials (Get-Credential) ``` -The URL should be the instance name portion of the FQDN for your instance. For if you browse to `https://myinstance.service-now.com` the URL required for the module is `myinstance.service-now.com`. +The URL should be the instance name portion of the FQDN for your instance. For if you browse to `https://yourinstance.service-now.com` the URL required for the module is `yourinstance.service-now.com`. ### Example - Retrieving an Incident Containing the Word 'PowerShell' From 092add11b3086447fc78b730a2d3bbedf648176a Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 26 Jan 2018 19:58:20 +0000 Subject: [PATCH 068/348] Update Set-ServiceNowAuth.ps1 --- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 47 ++++++++++++++++++------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index a5c0f2c..d0d91d1 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -1,22 +1,45 @@ +<# +.SYNOPSIS +Set your Service-Now authentication credentials + +.DESCRIPTION +This cmdlet will set your Service-Now authentication credentials which will enable you to interact with Service-Now using the other cmdlets in the module + +.PARAMETER Url +The URL of your Service-Now instance + +.PARAMETER Credentials +Credentials to authenticate you to the Service-Now instance provided in the Url parameter + +.EXAMPLE +Set-ServiceNowAuth -Url tenant.service-now.com + +.NOTES +The URL should be the instance name portion of the FQDN for your instance. If you browse to https://yourinstance.service-now.com the URL required for the module is yourinstance.service-now.com +#> function Set-ServiceNowAuth { [CmdletBinding()] - param( - [parameter(mandatory = $true)] + Param ( + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [ValidateScript( { if ($_ -notlike 'https://*') { + [ValidateScript( { + if ($_ -match '^\w+\..*\.\w+') { $true } else { - Throw "Please exclude https:// from your URL parameter: $_ " - } })] - [string]$url, - - [parameter(mandatory = $true)] + Throw "The expected URL format is tenant.domain.com" + } + })] + [string] + $Url, + + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [System.Management.Automation.PSCredential]$Credentials + [System.Management.Automation.PSCredential] + $Credentials ) - $Global:ServiceNowURL = 'https://' + $url - $Global:ServiceNowRESTURL = $ServiceNowURL + '/api/now/v1' - $Global:ServiceNowCredentials = $credentials + $Global:serviceNowUrl = 'https://' + $Url + $Global:serviceNowRestUrl = $serviceNowUrl + '/api/now/v1' + $Global:serviceNowCredentials = $Credentials return $true } From 3540a0caddf39eb24fef2b22c9a050ccba65bd02 Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 26 Jan 2018 23:02:36 +0000 Subject: [PATCH 069/348] Update Update-ServiceNowChangeRequest.ps1 --- ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 index ef733b2..8323f3f 100644 --- a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 @@ -5,7 +5,7 @@ function Update-ServiceNowChangeRequest { Param( - # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) + # sys_id of the caller of the incident (use Get-ServiceNowUser to retrieve this) [parameter(Mandatory=$true)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] @@ -50,4 +50,4 @@ function Update-ServiceNowChangeRequest } Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat -} \ No newline at end of file +} From f03f084cf9910db0b617aa72c4164b27b659f5c9 Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 26 Jan 2018 23:03:29 +0000 Subject: [PATCH 070/348] Update Update-ServiceNowIncident.ps1 --- ServiceNow/Public/Update-ServiceNowIncident.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/Public/Update-ServiceNowIncident.ps1 b/ServiceNow/Public/Update-ServiceNowIncident.ps1 index 9ed4f43..a0bf4ba 100644 --- a/ServiceNow/Public/Update-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Update-ServiceNowIncident.ps1 @@ -1,6 +1,6 @@ function Update-ServiceNowIncident { Param - ( # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) + ( # sys_id of the caller of the incident (use Get-ServiceNowUser to retrieve this) [parameter(mandatory=$true)] [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] From 0a3950baf47f344395878696e77421db5666bb34 Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Fri, 26 Jan 2018 23:04:44 +0000 Subject: [PATCH 071/348] Update Update-ServiceNowTableEntry.ps1 --- ServiceNow/Public/Update-ServiceNowTableEntry.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 index c38e433..c202643 100644 --- a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 @@ -25,7 +25,7 @@ function Update-ServiceNowTableEntry{ [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable]$Connection, @@ -38,7 +38,7 @@ function Update-ServiceNowTableEntry{ [hashtable]$Values ) - #Get credential and ServiceNow REST URL + # Get credential and ServiceNow REST URL if ($Connection -ne $null) { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force @@ -62,10 +62,10 @@ function Update-ServiceNowTableEntry{ $Body = $Values | ConvertTo-Json - #Convert to UTF8 array to support special chars such as the danish "�","�","�" + # 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 +} From d217b8cca47d37c5a8d3f775b7cb29c4b08e93c1 Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Sat, 24 Feb 2018 18:38:42 +0000 Subject: [PATCH 072/348] Rename Get-ServiceNowRequest to Get-ServiceNowRequest.ps1 --- .../Public/{Get-ServiceNowRequest => Get-ServiceNowRequest.ps1} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ServiceNow/Public/{Get-ServiceNowRequest => Get-ServiceNowRequest.ps1} (100%) diff --git a/ServiceNow/Public/Get-ServiceNowRequest b/ServiceNow/Public/Get-ServiceNowRequest.ps1 similarity index 100% rename from ServiceNow/Public/Get-ServiceNowRequest rename to ServiceNow/Public/Get-ServiceNowRequest.ps1 From 8319bbb3681beef1d7c91f5a780cba29205004d0 Mon Sep 17 00:00:00 2001 From: GilmondRoss Date: Sat, 24 Feb 2018 18:42:43 +0000 Subject: [PATCH 073/348] Update ServiceNow.psd1 --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index d36b962..5322032 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From 705f8aa1274e9b4d816f38f7ec2dbfecc9738b86 Mon Sep 17 00:00:00 2001 From: admcSHx - Simon Heather ADM Date: Tue, 27 Feb 2018 13:43:00 +0000 Subject: [PATCH 074/348] Change DisplayValues parameter to default to false --- ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowUser.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 28329f8..8fc4d0a 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowChangeRequest { [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 780645a..d31020e 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowConfigurationItem { [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 1823a27..f93b8ae 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowIncident{ [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 68113cd..c2d3b64 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowUser{ [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 24f7171..06165bb 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowUserGroup{ [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] From 9c0347dd3246cb75b43df4bd9242ebb4463b024e Mon Sep 17 00:00:00 2001 From: admcSHx - Simon Heather ADM Date: Tue, 27 Feb 2018 13:45:01 +0000 Subject: [PATCH 075/348] Add DateFormat global variable and comment based help --- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 31 +++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index 08f3a74..d9b53ce 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -1,13 +1,38 @@ function Set-ServiceNowAuth{ - param( +<# +.SYNOPSIS + Configures default connection settings for the Service-Now Instance +.DESCRIPTION + The Set-ServiceNowAuth function configures default connection settings for the Service-Now Instance. These include the instance URL, + authentication credentials and date format. +.INPUTS + None +.OUTPUTS + System.Boolean +.LINK + Service-Now Kingston Release REST API Reference: https://docs.servicenow.com/bundle/kingston-application-development/page/build/applications/concept/api-rest.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 +#> +param( + # The URL for the ServiceNow instance being used [parameter(mandatory=$true)] [string]$url, + # Credential used to authenticate to ServiceNow [parameter(mandatory=$true)] - [System.Management.Automation.PSCredential]$Credentials - ) + [System.Management.Automation.PSCredential]$Credentials, + + # The date format specified in the Service-Now Instance, sys_properties table, property glide.sys.data_format. This is required + # to correctly convert datetime fields to the local computer locale format when the DisplayValues parameter of the Get-* functions + # is set to true + [parameter(mandatory=$false)] + [String]$DateFormat=(Get-Culture).DateTimeFormat.ShortDatePattern+' '+(Get-Culture).DateTimeFormat.LongTimePattern + ) + $Global:ServiceNowURL = 'https://' + $url $Global:ServiceNowRESTURL = $ServiceNowURL + '/api/now/v1' $Global:ServiceNowCredentials = $credentials + $Global:ServiceNowDateFormat = $DateFormat + return $true; } From f4e1dbf3eb476072a9f1a9b9a8f67b50bf336917 Mon Sep 17 00:00:00 2001 From: admcSHx - Simon Heather ADM Date: Tue, 27 Feb 2018 13:46:21 +0000 Subject: [PATCH 076/348] modify datetime field processing and add comment based help --- ServiceNow/Public/Get-ServiceNowTable.ps1 | 43 +++++++++++++++-------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index d80f929..5f1209e 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -1,5 +1,18 @@ function Get-ServiceNowTable { - [OutputType([Array])] +<# +.SYNOPSIS + Retrieves multiple records for the specified table +.DESCRIPTION + The Get-ServiceNowTable function retrieves multiple records for the specified table +.INPUTS + None +.OUTPUTS + System.Management.Automation.PSCustomObject +.LINK + Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 +#> +[OutputType([Array])] Param ( # Name of the table we're querying (e.g. incidents) [parameter(Mandatory)] @@ -21,7 +34,7 @@ function Get-ServiceNowTable { [parameter(ParameterSetName = 'SetGlobalAuth')] [int]$Limit = 10, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(ParameterSetName = 'SpecifyConnectionFields')] [parameter(ParameterSetName = 'UseConnectionObject')] [parameter(ParameterSetName = 'SetGlobalAuth')] @@ -59,6 +72,7 @@ function Get-ServiceNowTable { elseif ((Test-ServiceNowAuthIsSet)) { $ServiceNowCredential = $Global:ServiceNowCredentials $ServiceNowURL = $global:ServiceNowRESTURL + $ServiceNowDateFormat = $Global:ServiceNowDateFormat } 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" @@ -75,28 +89,27 @@ function Get-ServiceNowTable { $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result # Convert specific fields to DateTime format + $DefaultServiceNowDateFormat = 'yyyy-MM-dd HH:mm:ss' $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') ForEach ($SNResult in $Result) { ForEach ($Property in $ConvertToDateField) { If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { - Try { - # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now - $CultureDateTimeFormat = (Get-Culture).DateTimeFormat - $DateFormat = $CultureDateTimeFormat.ShortDatePattern - $TimeFormat = $CultureDateTimeFormat.LongTimePattern - $DateTimeFormat = "$DateFormat $TimeFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } - Catch { + If ($DisplayValues -eq $True) { + # DateTime fields returned in the Service-Now instance system date format need converting to the local computers "culture" setting based upon the format specified Try { - # Universal Format - $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + Write-Debug "Date Parsing field: $Property, value: $($SNResult.$Property) against global format $Global:ServiceNowDateFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $Global:ServiceNowDateFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo) } Catch { - # If the local culture and universal formats both fail keep the property as a string (Do nothing) + Throw "Problem parsing date-time field $Property with value $($SNResult.$Property) against format $Global:ServiceNowDateFormat. " + + "Please verify the DateFormat parameter matches the glide.sys.date_format property of the Service-Now instance" } } + Else { + # DateTime fields always returned as yyyy-MM-dd hh:mm:ss when sysparm_display_value is set to false + Write-Debug "Date Parsing field: $Property, value: $($SNResult.$Property) against default format $DefaultServiceNowDateFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DefaultServiceNowDateFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo) + } } } } From ba26ed98f4781cf916a785e2d423241c0e03aae3 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 6 Mar 2018 21:07:38 -0600 Subject: [PATCH 077/348] Added basic Pester test for Get-ServiceNowRequest --- Tests/ServiceNow.Tests.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index c438e45..cc82fe9 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -75,6 +75,11 @@ Describe "ServiceNow-Module" { (Get-ServiceNowIncident).Count -gt 0 | Should -Match $true } + It "Get-ServiceNowRequest works" { + # There should be one or more incidents returned + (Get-ServiceNowRequest).Count -gt 0 | Should -Match $true + } + It "Update-ServiceNowIncident works" { $ShortDescription = "Testing Ticket Update with Pester" $newServiceNowIncidentSplat = @{ From aa3f60509cd1944a7588e96634e618faf3b88c1c Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 6 Mar 2018 21:54:56 -0600 Subject: [PATCH 078/348] Updated Pester tests to return an array in case there's only one object. --- Tests/ServiceNow.Tests.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index cc82fe9..a375b10 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -67,17 +67,17 @@ Describe "ServiceNow-Module" { It "Get-ServiceNowTable works" { # There should be one or more incidents returned - (Get-ServiceNowTable -Table 'incident' -Query 'ORDERBYDESCopened_at').Count -gt 0 | Should -Match $true + ([array](Get-ServiceNowTable -Table 'incident' -Query 'ORDERBYDESCopened_at')).Count -gt 0 | Should -Match $true } It "Get-ServiceNowIncident works" { # There should be one or more incidents returned - (Get-ServiceNowIncident).Count -gt 0 | Should -Match $true + ([array](Get-ServiceNowIncident)).count -gt 0 | Should -Match $true } It "Get-ServiceNowRequest works" { # There should be one or more incidents returned - (Get-ServiceNowRequest).Count -gt 0 | Should -Match $true + ([array](Get-ServiceNowRequest)).count -gt 0 | Should -Match $true } It "Update-ServiceNowIncident works" { From 4d10b2d0d5a64a41e9009fa0c8eeae914b0af554 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 6 Mar 2018 21:55:50 -0600 Subject: [PATCH 079/348] v1.0.2 ReadMe/psd1 incrementation --- Readme.md | 2 +- ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 5a966a7..d3f1f5f 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-73%25-orange.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-74%25-orange.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. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 5322032..494a495 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.0.1' +ModuleVersion = '1.0.2' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 855c9eec24d523cb776db685bb7c49276224b43a Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 7 Mar 2018 14:40:04 -0600 Subject: [PATCH 080/348] v1.1.0 - Incremented minor version to account for new function --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 494a495..4ec5cdf 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.0.2' +ModuleVersion = '1.1.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 52a8e719a69158a1e01ff48ea1b1139a4426c6bd Mon Sep 17 00:00:00 2001 From: Sam Martin Date: Fri, 25 May 2018 13:18:16 +0100 Subject: [PATCH 081/348] Update Readme.md --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index d3f1f5f..6c9ed56 100644 --- a/Readme.md +++ b/Readme.md @@ -103,4 +103,4 @@ This module has been created as an abstraction layer to suit my immediate requir ## Author -Author:: Sam Martin () +Author:: Sam Martin From 11162c9ad483dfb79364f641e62c86b7d18f0e79 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 6 Jul 2018 09:27:34 -0500 Subject: [PATCH 082/348] Reversed most of #26 after testing --- .../Public/Get-ServiceNowChangeRequest.ps1 | 22 ++++---- .../Get-ServiceNowConfigurationItem.ps1 | 18 +++--- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 24 ++++---- ServiceNow/Public/Get-ServiceNowTable.ps1 | 55 ++++++++++--------- ServiceNow/Public/Get-ServiceNowUser.ps1 | 24 ++++---- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 24 ++++---- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 18 +----- 7 files changed, 85 insertions(+), 100 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 8fc4d0a..c49c1d3 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowChangeRequest { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='opened_at', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowChangeRequest { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,24 +42,24 @@ function Get-ServiceNowChangeRequest { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection ) - + # Query Splat $newServiceNowQuerySplat = @{ OrderBy = $OrderBy @@ -68,7 +68,7 @@ function Get-ServiceNowChangeRequest { MatchContains = $MatchContains } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - + # Table Splat $getServiceNowTableSplat = @{ Table = 'change_request' @@ -79,10 +79,10 @@ function Get-ServiceNowChangeRequest { # Update the Table Splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) @@ -92,4 +92,4 @@ function Get-ServiceNowChangeRequest { $Result = Get-ServiceNowTable @getServiceNowTableSplat $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ChangeRequest")} $Result -} \ No newline at end of file +} diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index d31020e..34cb727 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowConfigurationItem { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='name', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowConfigurationItem { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,19 +42,19 @@ function Get-ServiceNowConfigurationItem { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -68,7 +68,7 @@ function Get-ServiceNowConfigurationItem { MatchContains = $MatchContains } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - + # Table Splat $getServiceNowTableSplat = @{ Table = 'cmdb_ci' @@ -79,10 +79,10 @@ function Get-ServiceNowConfigurationItem { # Update the Table Splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index f93b8ae..993c0c8 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowIncident{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='opened_at', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowIncident{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,22 +42,22 @@ function Get-ServiceNowIncident{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', - # Credential used to authenticate to ServiceNow + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, - # The URL for the ServiceNow instance being used + # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -72,20 +72,20 @@ function Get-ServiceNowIncident{ } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - # Table Splat + # Table Splat $getServiceNowTableSplat = @{ Table = 'incident' Query = $Query Limit = $Limit DisplayValues = $DisplayValues } - + # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 5f1209e..36f7289 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -1,18 +1,19 @@ function Get-ServiceNowTable { <# -.SYNOPSIS - Retrieves multiple records for the specified table -.DESCRIPTION - The Get-ServiceNowTable function retrieves multiple records for the specified table -.INPUTS - None -.OUTPUTS - System.Management.Automation.PSCustomObject -.LINK - Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html - Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 + .SYNOPSIS + Retrieves records for the specified table + .DESCRIPTION + The Get-ServiceNowTable function retrieves records for the specified table + .INPUTS + None + .OUTPUTS + System.Management.Automation.PSCustomObject + .LINK + Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 #> -[OutputType([Array])] + + [OutputType([System.Management.Automation.PSCustomObject])] Param ( # Name of the table we're querying (e.g. incidents) [parameter(Mandatory)] @@ -34,12 +35,12 @@ function Get-ServiceNowTable { [parameter(ParameterSetName = 'SetGlobalAuth')] [int]$Limit = 10, - # Whether to return manipulated display values rather than actual database values. + # Whether or not to show human readable display values instead of machine values [parameter(ParameterSetName = 'SpecifyConnectionFields')] [parameter(ParameterSetName = 'UseConnectionObject')] [parameter(ParameterSetName = 'SetGlobalAuth')] [ValidateSet("true", "false", "all")] - [string]$DisplayValues = 'false', + [string]$DisplayValues = 'true', # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName = 'SpecifyConnectionFields')] @@ -72,7 +73,6 @@ function Get-ServiceNowTable { elseif ((Test-ServiceNowAuthIsSet)) { $ServiceNowCredential = $Global:ServiceNowCredentials $ServiceNowURL = $global:ServiceNowRESTURL - $ServiceNowDateFormat = $Global:ServiceNowDateFormat } 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" @@ -89,27 +89,28 @@ function Get-ServiceNowTable { $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result # Convert specific fields to DateTime format - $DefaultServiceNowDateFormat = 'yyyy-MM-dd HH:mm:ss' $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') ForEach ($SNResult in $Result) { ForEach ($Property in $ConvertToDateField) { If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { - If ($DisplayValues -eq $True) { - # DateTime fields returned in the Service-Now instance system date format need converting to the local computers "culture" setting based upon the format specified + Try { + # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now + $CultureDateTimeFormat = (Get-Culture).DateTimeFormat + $DateFormat = $CultureDateTimeFormat.ShortDatePattern + $TimeFormat = $CultureDateTimeFormat.LongTimePattern + $DateTimeFormat = "$DateFormat $TimeFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } + Catch { Try { - Write-Debug "Date Parsing field: $Property, value: $($SNResult.$Property) against global format $Global:ServiceNowDateFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $Global:ServiceNowDateFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo) + # Universal Format + $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) } Catch { - Throw "Problem parsing date-time field $Property with value $($SNResult.$Property) against format $Global:ServiceNowDateFormat. " + - "Please verify the DateFormat parameter matches the glide.sys.date_format property of the Service-Now instance" + # If the local culture and universal formats both fail keep the property as a string (Do nothing) } } - Else { - # DateTime fields always returned as yyyy-MM-dd hh:mm:ss when sysparm_display_value is set to false - Write-Debug "Date Parsing field: $Property, value: $($SNResult.$Property) against default format $DefaultServiceNowDateFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DefaultServiceNowDateFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo) - } } } } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index c2d3b64..2c31075 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowUser{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='name', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowUser{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,22 +42,22 @@ function Get-ServiceNowUser{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', - # Credential used to authenticate to ServiceNow + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, - # The URL for the ServiceNow instance being used + # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -72,20 +72,20 @@ function Get-ServiceNowUser{ } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - # Table Splat + # Table Splat $getServiceNowTableSplat = @{ Table = 'sys_user' Query = $Query Limit = $Limit DisplayValues = $DisplayValues } - + # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 06165bb..42af0f6 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowUserGroup{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='name', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowUserGroup{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,22 +42,22 @@ function Get-ServiceNowUserGroup{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', - # Credential used to authenticate to ServiceNow + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, - # The URL for the ServiceNow instance being used + # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -72,20 +72,20 @@ function Get-ServiceNowUserGroup{ } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - # Table Splat + # Table Splat $getServiceNowTableSplat = @{ Table = 'sys_user_group' Query = $Query Limit = $Limit DisplayValues = $DisplayValues } - + # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index 05ec8e2..d0d91d1 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -11,20 +11,11 @@ The URL of your Service-Now instance .PARAMETER Credentials Credentials to authenticate you to the Service-Now instance provided in the Url parameter -.PARAMETER DateFormat -The date format specified in the Service-Now Instance, sys_properties table, property glide.sys.data_format. This is required -to correctly convert datetime fields to the local computer locale format when the DisplayValues parameter of the Get-* functions -is set to true - .EXAMPLE Set-ServiceNowAuth -Url tenant.service-now.com .NOTES The URL should be the instance name portion of the FQDN for your instance. If you browse to https://yourinstance.service-now.com the URL required for the module is yourinstance.service-now.com - -.LINK - Service-Now Kingston Release REST API Reference: https://docs.servicenow.com/bundle/kingston-application-development/page/build/applications/concept/api-rest.html - Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 #> function Set-ServiceNowAuth { [CmdletBinding()] @@ -45,17 +36,10 @@ function Set-ServiceNowAuth { [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCredential] - $Credentials, - - [parameter(mandatory = $false)] - [String] - $DateFormat = (Get-Culture).DateTimeFormat.ShortDatePattern+' '+(Get-Culture).DateTimeFormat.LongTimePattern + $Credentials ) - $Global:serviceNowUrl = 'https://' + $Url $Global:serviceNowRestUrl = $serviceNowUrl + '/api/now/v1' $Global:serviceNowCredentials = $Credentials - $Global:ServiceNowDateFormat = $DateFormat - return $true } From 3155e28e123f4d4dfa3984b354074f7abfdd878e Mon Sep 17 00:00:00 2001 From: admcSHx - Simon Heather ADM Date: Tue, 27 Feb 2018 13:43:00 +0000 Subject: [PATCH 083/348] Change DisplayValues parameter to default to false --- ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowUser.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 28329f8..8fc4d0a 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowChangeRequest { [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 780645a..d31020e 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowConfigurationItem { [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 1823a27..f93b8ae 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowIncident{ [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 68113cd..c2d3b64 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowUser{ [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 24f7171..06165bb 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -36,13 +36,13 @@ function Get-ServiceNowUserGroup{ [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$MatchContains=@{}, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + [string]$DisplayValues='false', # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] From 9c57c239b8f8dbe0b60a4ef88bee74efebd3579c Mon Sep 17 00:00:00 2001 From: admcSHx - Simon Heather ADM Date: Tue, 27 Feb 2018 13:45:01 +0000 Subject: [PATCH 084/348] Add DateFormat global variable and comment based help --- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 40 ++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index d0d91d1..3072de7 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -1,3 +1,4 @@ +<<<<<<< HEAD <# .SYNOPSIS Set your Service-Now authentication credentials @@ -42,4 +43,43 @@ function Set-ServiceNowAuth { $Global:serviceNowRestUrl = $serviceNowUrl + '/api/now/v1' $Global:serviceNowCredentials = $Credentials return $true +======= +function Set-ServiceNowAuth{ +<# +.SYNOPSIS + Configures default connection settings for the Service-Now Instance +.DESCRIPTION + The Set-ServiceNowAuth function configures default connection settings for the Service-Now Instance. These include the instance URL, + authentication credentials and date format. +.INPUTS + None +.OUTPUTS + System.Boolean +.LINK + Service-Now Kingston Release REST API Reference: https://docs.servicenow.com/bundle/kingston-application-development/page/build/applications/concept/api-rest.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 +#> +param( + # The URL for the ServiceNow instance being used + [parameter(mandatory=$true)] + [string]$url, + + # Credential used to authenticate to ServiceNow + [parameter(mandatory=$true)] + [System.Management.Automation.PSCredential]$Credentials, + + # The date format specified in the Service-Now Instance, sys_properties table, property glide.sys.data_format. This is required + # to correctly convert datetime fields to the local computer locale format when the DisplayValues parameter of the Get-* functions + # is set to true + [parameter(mandatory=$false)] + [String]$DateFormat=(Get-Culture).DateTimeFormat.ShortDatePattern+' '+(Get-Culture).DateTimeFormat.LongTimePattern + ) + + $Global:ServiceNowURL = 'https://' + $url + $Global:ServiceNowRESTURL = $ServiceNowURL + '/api/now/v1' + $Global:ServiceNowCredentials = $credentials + $Global:ServiceNowDateFormat = $DateFormat + + return $true; +>>>>>>> Add DateFormat global variable and comment based help } From e616068d817664dcca921875b52d223b6b6ae5ee Mon Sep 17 00:00:00 2001 From: admcSHx - Simon Heather ADM Date: Tue, 27 Feb 2018 13:46:21 +0000 Subject: [PATCH 085/348] modify datetime field processing and add comment based help --- ServiceNow/Public/Get-ServiceNowTable.ps1 | 43 +++++++++++++++-------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index d80f929..5f1209e 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -1,5 +1,18 @@ function Get-ServiceNowTable { - [OutputType([Array])] +<# +.SYNOPSIS + Retrieves multiple records for the specified table +.DESCRIPTION + The Get-ServiceNowTable function retrieves multiple records for the specified table +.INPUTS + None +.OUTPUTS + System.Management.Automation.PSCustomObject +.LINK + Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 +#> +[OutputType([Array])] Param ( # Name of the table we're querying (e.g. incidents) [parameter(Mandatory)] @@ -21,7 +34,7 @@ function Get-ServiceNowTable { [parameter(ParameterSetName = 'SetGlobalAuth')] [int]$Limit = 10, - # Whether or not to show human readable display values instead of machine values + # Whether to return manipulated display values rather than actual database values. [parameter(ParameterSetName = 'SpecifyConnectionFields')] [parameter(ParameterSetName = 'UseConnectionObject')] [parameter(ParameterSetName = 'SetGlobalAuth')] @@ -59,6 +72,7 @@ function Get-ServiceNowTable { elseif ((Test-ServiceNowAuthIsSet)) { $ServiceNowCredential = $Global:ServiceNowCredentials $ServiceNowURL = $global:ServiceNowRESTURL + $ServiceNowDateFormat = $Global:ServiceNowDateFormat } 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" @@ -75,28 +89,27 @@ function Get-ServiceNowTable { $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result # Convert specific fields to DateTime format + $DefaultServiceNowDateFormat = 'yyyy-MM-dd HH:mm:ss' $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') ForEach ($SNResult in $Result) { ForEach ($Property in $ConvertToDateField) { If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { - Try { - # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now - $CultureDateTimeFormat = (Get-Culture).DateTimeFormat - $DateFormat = $CultureDateTimeFormat.ShortDatePattern - $TimeFormat = $CultureDateTimeFormat.LongTimePattern - $DateTimeFormat = "$DateFormat $TimeFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } - Catch { + If ($DisplayValues -eq $True) { + # DateTime fields returned in the Service-Now instance system date format need converting to the local computers "culture" setting based upon the format specified Try { - # Universal Format - $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + Write-Debug "Date Parsing field: $Property, value: $($SNResult.$Property) against global format $Global:ServiceNowDateFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $Global:ServiceNowDateFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo) } Catch { - # If the local culture and universal formats both fail keep the property as a string (Do nothing) + Throw "Problem parsing date-time field $Property with value $($SNResult.$Property) against format $Global:ServiceNowDateFormat. " + + "Please verify the DateFormat parameter matches the glide.sys.date_format property of the Service-Now instance" } } + Else { + # DateTime fields always returned as yyyy-MM-dd hh:mm:ss when sysparm_display_value is set to false + Write-Debug "Date Parsing field: $Property, value: $($SNResult.$Property) against default format $DefaultServiceNowDateFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DefaultServiceNowDateFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo) + } } } } From 431c403a1f62dbfdb1e41beaf4566e2922e29ce2 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 6 Jul 2018 09:27:34 -0500 Subject: [PATCH 086/348] Reversed most of #26 after testing --- .../Public/Get-ServiceNowChangeRequest.ps1 | 22 ++++---- .../Get-ServiceNowConfigurationItem.ps1 | 18 +++--- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 24 ++++---- ServiceNow/Public/Get-ServiceNowTable.ps1 | 55 ++++++++++--------- ServiceNow/Public/Get-ServiceNowUser.ps1 | 24 ++++---- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 24 ++++---- 6 files changed, 84 insertions(+), 83 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 8fc4d0a..c49c1d3 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowChangeRequest { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='opened_at', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowChangeRequest { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,24 +42,24 @@ function Get-ServiceNowChangeRequest { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection ) - + # Query Splat $newServiceNowQuerySplat = @{ OrderBy = $OrderBy @@ -68,7 +68,7 @@ function Get-ServiceNowChangeRequest { MatchContains = $MatchContains } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - + # Table Splat $getServiceNowTableSplat = @{ Table = 'change_request' @@ -79,10 +79,10 @@ function Get-ServiceNowChangeRequest { # Update the Table Splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) @@ -92,4 +92,4 @@ function Get-ServiceNowChangeRequest { $Result = Get-ServiceNowTable @getServiceNowTableSplat $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ChangeRequest")} $Result -} \ No newline at end of file +} diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index d31020e..34cb727 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowConfigurationItem { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='name', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowConfigurationItem { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,19 +42,19 @@ function Get-ServiceNowConfigurationItem { [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -68,7 +68,7 @@ function Get-ServiceNowConfigurationItem { MatchContains = $MatchContains } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - + # Table Splat $getServiceNowTableSplat = @{ Table = 'cmdb_ci' @@ -79,10 +79,10 @@ function Get-ServiceNowConfigurationItem { # Update the Table Splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index f93b8ae..993c0c8 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowIncident{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='opened_at', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowIncident{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,22 +42,22 @@ function Get-ServiceNowIncident{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', - # Credential used to authenticate to ServiceNow + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, - # The URL for the ServiceNow instance being used + # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -72,20 +72,20 @@ function Get-ServiceNowIncident{ } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - # Table Splat + # Table Splat $getServiceNowTableSplat = @{ Table = 'incident' Query = $Query Limit = $Limit DisplayValues = $DisplayValues } - + # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 5f1209e..36f7289 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -1,18 +1,19 @@ function Get-ServiceNowTable { <# -.SYNOPSIS - Retrieves multiple records for the specified table -.DESCRIPTION - The Get-ServiceNowTable function retrieves multiple records for the specified table -.INPUTS - None -.OUTPUTS - System.Management.Automation.PSCustomObject -.LINK - Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html - Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 + .SYNOPSIS + Retrieves records for the specified table + .DESCRIPTION + The Get-ServiceNowTable function retrieves records for the specified table + .INPUTS + None + .OUTPUTS + System.Management.Automation.PSCustomObject + .LINK + Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 #> -[OutputType([Array])] + + [OutputType([System.Management.Automation.PSCustomObject])] Param ( # Name of the table we're querying (e.g. incidents) [parameter(Mandatory)] @@ -34,12 +35,12 @@ function Get-ServiceNowTable { [parameter(ParameterSetName = 'SetGlobalAuth')] [int]$Limit = 10, - # Whether to return manipulated display values rather than actual database values. + # Whether or not to show human readable display values instead of machine values [parameter(ParameterSetName = 'SpecifyConnectionFields')] [parameter(ParameterSetName = 'UseConnectionObject')] [parameter(ParameterSetName = 'SetGlobalAuth')] [ValidateSet("true", "false", "all")] - [string]$DisplayValues = 'false', + [string]$DisplayValues = 'true', # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName = 'SpecifyConnectionFields')] @@ -72,7 +73,6 @@ function Get-ServiceNowTable { elseif ((Test-ServiceNowAuthIsSet)) { $ServiceNowCredential = $Global:ServiceNowCredentials $ServiceNowURL = $global:ServiceNowRESTURL - $ServiceNowDateFormat = $Global:ServiceNowDateFormat } 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" @@ -89,27 +89,28 @@ function Get-ServiceNowTable { $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result # Convert specific fields to DateTime format - $DefaultServiceNowDateFormat = 'yyyy-MM-dd HH:mm:ss' $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') ForEach ($SNResult in $Result) { ForEach ($Property in $ConvertToDateField) { If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { - If ($DisplayValues -eq $True) { - # DateTime fields returned in the Service-Now instance system date format need converting to the local computers "culture" setting based upon the format specified + Try { + # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now + $CultureDateTimeFormat = (Get-Culture).DateTimeFormat + $DateFormat = $CultureDateTimeFormat.ShortDatePattern + $TimeFormat = $CultureDateTimeFormat.LongTimePattern + $DateTimeFormat = "$DateFormat $TimeFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } + Catch { Try { - Write-Debug "Date Parsing field: $Property, value: $($SNResult.$Property) against global format $Global:ServiceNowDateFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $Global:ServiceNowDateFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo) + # Universal Format + $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) } Catch { - Throw "Problem parsing date-time field $Property with value $($SNResult.$Property) against format $Global:ServiceNowDateFormat. " + - "Please verify the DateFormat parameter matches the glide.sys.date_format property of the Service-Now instance" + # If the local culture and universal formats both fail keep the property as a string (Do nothing) } } - Else { - # DateTime fields always returned as yyyy-MM-dd hh:mm:ss when sysparm_display_value is set to false - Write-Debug "Date Parsing field: $Property, value: $($SNResult.$Property) against default format $DefaultServiceNowDateFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DefaultServiceNowDateFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo) - } } } } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index c2d3b64..2c31075 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowUser{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='name', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowUser{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,22 +42,22 @@ function Get-ServiceNowUser{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', - # Credential used to authenticate to ServiceNow + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, - # The URL for the ServiceNow instance being used + # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -72,20 +72,20 @@ function Get-ServiceNowUser{ } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - # Table Splat + # Table Splat $getServiceNowTableSplat = @{ Table = 'sys_user' Query = $Query Limit = $Limit DisplayValues = $DisplayValues } - + # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 06165bb..42af0f6 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -6,7 +6,7 @@ function Get-ServiceNowUserGroup{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$OrderBy='name', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -21,7 +21,7 @@ function Get-ServiceNowUserGroup{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [int]$Limit=10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -42,22 +42,22 @@ function Get-ServiceNowUserGroup{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [ValidateSet("true","false", "all")] - [string]$DisplayValues='false', + [string]$DisplayValues='true', - # Credential used to authenticate to ServiceNow + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, - # The URL for the ServiceNow instance being used + # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection @@ -72,20 +72,20 @@ function Get-ServiceNowUserGroup{ } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - # Table Splat + # Table Splat $getServiceNowTableSplat = @{ Table = 'sys_user_group' Query = $Query Limit = $Limit DisplayValues = $DisplayValues } - + # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) From 6dcb406785821a3090abf827ad1ab30158c69642 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 6 Jul 2018 10:14:16 -0500 Subject: [PATCH 087/348] Moved help to make vscode happy --- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 66 +++++------------------- 1 file changed, 13 insertions(+), 53 deletions(-) diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index 3072de7..3e9bdc6 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -1,24 +1,23 @@ -<<<<<<< HEAD +function Set-ServiceNowAuth { <# -.SYNOPSIS -Set your Service-Now authentication credentials + .SYNOPSIS + Set your Service-Now authentication credentials -.DESCRIPTION -This cmdlet will set your Service-Now authentication credentials which will enable you to interact with Service-Now using the other cmdlets in the module + .DESCRIPTION + This cmdlet will set your Service-Now authentication credentials which will enable you to interact with Service-Now using the other cmdlets in the module -.PARAMETER Url -The URL of your Service-Now instance + .PARAMETER Url + The URL of your Service-Now instance -.PARAMETER Credentials -Credentials to authenticate you to the Service-Now instance provided in the Url parameter + .PARAMETER Credentials + Credentials to authenticate you to the Service-Now instance provided in the Url parameter -.EXAMPLE -Set-ServiceNowAuth -Url tenant.service-now.com + .EXAMPLE + Set-ServiceNowAuth -Url tenant.service-now.com -.NOTES -The URL should be the instance name portion of the FQDN for your instance. If you browse to https://yourinstance.service-now.com the URL required for the module is yourinstance.service-now.com + .NOTES + The URL should be the instance name portion of the FQDN for your instance. If you browse to https://yourinstance.service-now.com the URL required for the module is yourinstance.service-now.com #> -function Set-ServiceNowAuth { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] @@ -43,43 +42,4 @@ function Set-ServiceNowAuth { $Global:serviceNowRestUrl = $serviceNowUrl + '/api/now/v1' $Global:serviceNowCredentials = $Credentials return $true -======= -function Set-ServiceNowAuth{ -<# -.SYNOPSIS - Configures default connection settings for the Service-Now Instance -.DESCRIPTION - The Set-ServiceNowAuth function configures default connection settings for the Service-Now Instance. These include the instance URL, - authentication credentials and date format. -.INPUTS - None -.OUTPUTS - System.Boolean -.LINK - Service-Now Kingston Release REST API Reference: https://docs.servicenow.com/bundle/kingston-application-development/page/build/applications/concept/api-rest.html - Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 -#> -param( - # The URL for the ServiceNow instance being used - [parameter(mandatory=$true)] - [string]$url, - - # Credential used to authenticate to ServiceNow - [parameter(mandatory=$true)] - [System.Management.Automation.PSCredential]$Credentials, - - # The date format specified in the Service-Now Instance, sys_properties table, property glide.sys.data_format. This is required - # to correctly convert datetime fields to the local computer locale format when the DisplayValues parameter of the Get-* functions - # is set to true - [parameter(mandatory=$false)] - [String]$DateFormat=(Get-Culture).DateTimeFormat.ShortDatePattern+' '+(Get-Culture).DateTimeFormat.LongTimePattern - ) - - $Global:ServiceNowURL = 'https://' + $url - $Global:ServiceNowRESTURL = $ServiceNowURL + '/api/now/v1' - $Global:ServiceNowCredentials = $credentials - $Global:ServiceNowDateFormat = $DateFormat - - return $true; ->>>>>>> Add DateFormat global variable and comment based help } From 98c53afa8d0cf947b3c59bd470ec041f7ea70fc4 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 21 Aug 2018 15:54:33 -0500 Subject: [PATCH 088/348] Add function Get-ServiceNowTableEntry --- .../Public/Get-ServiceNowTableEntry.ps1 | 117 ++++++++++++++++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 ServiceNow/Public/Get-ServiceNowTableEntry.ps1 diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 new file mode 100644 index 0000000..7989d85 --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -0,0 +1,117 @@ +function Get-ServiceNowTableEntry { + <# + .SYNOPSIS + Wraps Get-ServiceNowQuery & Get-ServiceNowTable for easier custom table queries + .DESCRIPTION + Wraps Get-ServiceNowQuery & Get-ServiceNowTable for easier custom table queries. No formatting is provided on output. Every property is returned by default. + .EXAMPLE + Get-ServiceNowTableEntry -Table sc_req_item -Limit 1 + + Returns one request item (RITM) from the sc_req_item table + .EXAMPLE + $Record = Get-ServiceNowTableEntry -Table u_customtable -MatchExact {number=$Number} + Update-ServiceNowTableEntry -SysID $Record.sys_id -Table u_customtable -Values {comments='Ticket updated'} + + Utilize the returned object data with to provide the sys_id property required for updates and removals + .OUTPUTS + System.Management.Automation.PSCustomObject + .NOTES + + #> + param( + # Table containing the entry we're deleting + [parameter(mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Table, + + # Machine name of the field to order by + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string]$OrderBy = 'opened_at', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection = 'Desc', + + # Maximum number of records to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [int]$Limit = 10, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [hashtable]$MatchExact = @{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [hashtable]$MatchContains = @{}, + + # Whether or not to show human readable display values instead of machine values + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [ValidateSet("true", "false", "all")] + [string]$DisplayValues = 'true', + + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [PSCredential] + $ServiceNowCredential, + + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [string] + $ServiceNowURL, + + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [Hashtable] + $Connection + ) + + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + MatchExact = $MatchExact + OrderDirection = $OrderDirection + MatchContains = $MatchContains + } + $Query = New-ServiceNowQuery @newServiceNowQuerySplat + + # Table Splat + $getServiceNowTableSplat = @{ + Table = $Table + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues + } + + # Update the Table Splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) { + $getServiceNowTableSplat.Add('Connection', $Connection) + } + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) + } + + # Perform table query and return each object. No fancy formatting here as this can pull tables with unknown default properties + Get-ServiceNowTable @getServiceNowTableSplat +} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 4ec5cdf..5a70709 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry''Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From 7b9a8eb0a5376d2e568526d414978ae4f52495e6 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 27 Aug 2018 10:49:12 -0500 Subject: [PATCH 089/348] Code read improvements, added error handling, and CBH example fix --- .../Public/Get-ServiceNowTableEntry.ps1 | 98 ++++++++----------- 1 file changed, 43 insertions(+), 55 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index 7989d85..b24cfbc 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -9,8 +9,8 @@ function Get-ServiceNowTableEntry { Returns one request item (RITM) from the sc_req_item table .EXAMPLE - $Record = Get-ServiceNowTableEntry -Table u_customtable -MatchExact {number=$Number} - Update-ServiceNowTableEntry -SysID $Record.sys_id -Table u_customtable -Values {comments='Ticket updated'} + $Record = Get-ServiceNowTableEntry -Table u_customtable -MatchExact @{number=$Number} + Update-ServiceNowTableEntry -SysID $Record.sys_id -Table u_customtable -Values @{comments='Ticket updated'} Utilize the returned object data with to provide the sys_id property required for updates and removals .OUTPUTS @@ -18,100 +18,88 @@ function Get-ServiceNowTableEntry { .NOTES #> + + [CmdletBinding(DefaultParameterSetName)] param( # Table containing the entry we're deleting [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] [string]$Table, # Machine name of the field to order by [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] [ValidateSet("Desc", "Asc")] [string]$OrderDirection = 'Desc', # Maximum number of records to return [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] [int]$Limit = 10, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] [ValidateSet("true", "false", "all")] [string]$DisplayValues = 'true', [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [string]$ServiceNowURL, [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - MatchExact = $MatchExact - OrderDirection = $OrderDirection - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = $Table - Query = $Query - Limit = $Limit - DisplayValues = $DisplayValues + Try { + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + MatchExact = $MatchExact + OrderDirection = $OrderDirection + MatchContains = $MatchContains + ErrorAction = 'Stop' + } + $Query = New-ServiceNowQuery @newServiceNowQuerySplat + + # Table Splat + $getServiceNowTableSplat = @{ + Table = $Table + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues + ErrorAction = 'Stop' + } + + # Update the Table Splat if an applicable parameter set name is in use + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $getServiceNowTableSplat.Add('ServiceNowCredential', $Credential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) + } + 'UseConnectionObject' { + $getServiceNowTableSplat.Add('Connection', $Connection) + } + } + + # Perform table query and return each object. No fancy formatting here as this can pull tables with unknown default properties + Get-ServiceNowTable @getServiceNowTableSplat } - - # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection', $Connection) + Catch { + Write-Error $PSItem } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - } - - # Perform table query and return each object. No fancy formatting here as this can pull tables with unknown default properties - Get-ServiceNowTable @getServiceNowTableSplat } From 386b35b0bdc7cbabed204902a564dee6f9d0779b Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 27 Aug 2018 12:04:52 -0500 Subject: [PATCH 090/348] Fixed missed comma in FunctionsToExport --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 5a70709..825d411 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry''Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From cd803f5d5b175b03aac4531b91ec52cfe1e3c01d Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 27 Aug 2018 17:27:33 -0500 Subject: [PATCH 091/348] Added default option to switch to suppress output --- ServiceNow/Public/Get-ServiceNowTableEntry.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index b24cfbc..d0bf297 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -94,6 +94,7 @@ function Get-ServiceNowTableEntry { 'UseConnectionObject' { $getServiceNowTableSplat.Add('Connection', $Connection) } + Default {} } # Perform table query and return each object. No fancy formatting here as this can pull tables with unknown default properties From 1213234df9284f648e74cb8d43783c4f89ec1544 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 5 Sep 2018 13:35:05 -0500 Subject: [PATCH 092/348] v1.2.0 - Incremented minor version for Get-ServiceNowTableEntry addition --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 825d411..20815e7 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.1.0' +ModuleVersion = '1.2.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 5704c1bbb01321da3828d327ef3adb207d816181 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 24 Sep 2018 12:37:15 -0500 Subject: [PATCH 093/348] Added Update-ServiceNowNumber --- ServiceNow/Public/Update-ServiceNowNumber.ps1 | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 ServiceNow/Public/Update-ServiceNowNumber.ps1 diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 new file mode 100644 index 0000000..8effa46 --- /dev/null +++ b/ServiceNow/Public/Update-ServiceNowNumber.ps1 @@ -0,0 +1,123 @@ +Function Update-ServiceNowNumber { + <# + .SYNOPSIS + Allows for the passing of a number and associated table to update a ServiceNow entry. + + .DESCRIPTION + Allows for the passing of a number and associated table to update a ServiceNow entry. Output is suppressed and may be returned with a switch parameter. + + .EXAMPLE + Update-ServiceNowNumber -Number $Number -Table $Table -Values @{property='value'} + + Updates a ticket number with a value providing no return output. + + .EXAMPLE + Update-ServiceNowNumber -Number $Number -Table $Table -Values @{property='value'} -PassThru + + Updates a ticket number with a value providing return output. + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + Param( + # Object number + [Parameter(Mandatory=$true)] + [string]$Number, + + # Table containing the entry + [Parameter(Mandatory=$true)] + [string]$Table, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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)] + [hashtable]$Values, + + # Switch to allow the results to be passed back + [parameter(Mandatory=$false)] + [switch]$PassThru + ) + + begin {} + process { + Try { + # Use the number and table to determine the sys_id + $getServiceNowTableEntry = @{ + Table = $Table + MatchExact = @{number = $number} + Credential = $Credential + ServiceNowURL = $ServiceNowURL + ErrorAction = 'Stop' + } + $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $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" + } + } + } + + # Convert the values to Json and encode them to an UTF8 array to support special chars + $Body = $Values | ConvertTo-Json + $utf8Bytes = [System.Text.Encoding]::Utf8.GetBytes($Body) + + # Setup splat + $Uri = $ServiceNowURL + "/table/$Table/$SysID" + $invokeRestMethodSplat = @{ + Uri = $uri + Method = 'Patch' + Credential = $Credential + Body = $utf8Bytes + ContentType = 'application/json' + } + + If ($PSCmdlet.ShouldProcess("$Table/$SysID",$MyInvocation.MyCommand)) { + # Send REST call + $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result + + # Option to return results + If ($PSBoundParameters.ContainsKey('Passthru')) { + $Result + } + } + } + Catch { + Write-Error $PSItem + } + } + end {} +} From c3fe1067b26c501e43a81974722b74fccef9e51f Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 24 Sep 2018 12:45:09 -0500 Subject: [PATCH 094/348] Clarified help synopsis & description --- ServiceNow/Public/Update-ServiceNowNumber.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 index 8effa46..58a7390 100644 --- a/ServiceNow/Public/Update-ServiceNowNumber.ps1 +++ b/ServiceNow/Public/Update-ServiceNowNumber.ps1 @@ -1,10 +1,10 @@ Function Update-ServiceNowNumber { <# .SYNOPSIS - Allows for the passing of a number and associated table to update a ServiceNow entry. + Allows for the passing of a number, instead of a sys_id, and associated table to update a ServiceNow entry. .DESCRIPTION - Allows for the passing of a number and associated table to update a ServiceNow entry. Output is suppressed and may be returned with a switch parameter. + Allows for the passing of a number, instead of a sys_id, and associated table to update a ServiceNow entry. Output is suppressed and may be returned with a switch parameter. .EXAMPLE Update-ServiceNowNumber -Number $Number -Table $Table -Values @{property='value'} From 5ae395613143b9e31be98247fe90c583267ec927 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 24 Sep 2018 15:46:52 -0500 Subject: [PATCH 095/348] Update psd1 with new function name --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 20815e7..3f0c46d 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From 3bd3bbd9ad55dc5cf3cac597403e194ad606e853 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 1 Oct 2018 17:06:07 -0500 Subject: [PATCH 096/348] v1.2.1 - Bug fix on Update-ServiceNowNumber --- ServiceNow/Public/Update-ServiceNowNumber.ps1 | 11 +++++++---- ServiceNow/ServiceNow.psd1 | 6 +++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 index 58a7390..14fa245 100644 --- a/ServiceNow/Public/Update-ServiceNowNumber.ps1 +++ b/ServiceNow/Public/Update-ServiceNowNumber.ps1 @@ -60,25 +60,25 @@ Function Update-ServiceNowNumber { begin {} process { Try { - # Use the number and table to determine the sys_id + # Prep a splat to use the provided number to find the sys_id $getServiceNowTableEntry = @{ Table = $Table MatchExact = @{number = $number} - Credential = $Credential - ServiceNowURL = $ServiceNowURL ErrorAction = 'Stop' } - $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id # Process credential steps based on parameter set name Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' + $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) + $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' + $updateServiceNowTableEntrySplat.Add('Connection',$Connection) } Default { If ((Test-ServiceNowAuthIsSet)) { @@ -91,6 +91,9 @@ Function Update-ServiceNowNumber { } } + # Use the number and table to determine the sys_id + $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + # Convert the values to Json and encode them to an UTF8 array to support special chars $Body = $Values | ConvertTo-Json $utf8Bytes = [System.Text.Encoding]::Utf8.GetBytes($Body) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 3f0c46d..da540c3 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.2.0' +ModuleVersion = '1.2.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -99,3 +99,7 @@ PrivateData = @{ # DefaultCommandPrefix = '' } + + + + From 8c384d742f6ce0b9f035810c4f42659b14960e86 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 1 Oct 2018 17:06:50 -0500 Subject: [PATCH 097/348] Build formatting changes. Pester test additions/edits. ReadMe Update. --- Build/psake.ps1 | 60 ++++++------- Readme.md | 7 +- Tests/ServiceNow.Tests.ps1 | 169 ++++++++++++++++++++++++++++--------- 3 files changed, 159 insertions(+), 77 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index e967ec5..a451eca 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -13,8 +13,7 @@ Properties { $lines = '----------------------------------------------------------------------' $Verbose = @{} - if($ENV:BHCommitMessage -match "!verbose") - { + if ($ENV:BHCommitMessage -match "!verbose") { $Verbose = @{Verbose = $True} } } @@ -30,23 +29,20 @@ Task Init { "`n" } - Task Analyze -Depends Init { $saResults = Invoke-ScriptAnalyzer -Path $ENV:BHModulePath -Severity @('Error', 'Warning') -Recurse -Verbose:$false if ($saResults) { - $saResults | Format-Table - #Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' + $saResults | Format-Table + # Write-Error -Message 'One or more Script Analyzer errors/warnings where found. Build cannot continue!' } } - Task UnitTests -Depends Init { $lines 'Running quick unit tests to fail early if there is an error' - $TestResults = Invoke-Pester -Path $ProjectRoot\Tests\*unit* -PassThru -Tag Build - - if($TestResults.FailedCount -gt 0) - { + $TestResults = Invoke-Pester -Path $ProjectRoot\Tests\*unit* -PassThru -Tag Build + + if($TestResults.FailedCount -gt 0) { Write-Error "Failed '$($TestResults.FailedCount)' tests, build failed" } "`n" @@ -63,13 +59,12 @@ Task Test -Depends UnitTests { $CodeCoverage.AddRange($CodeFiles.FullName) $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath - # In Appveyor? Upload our tests! #Abstract this into a function? - If($ENV:BHBuildSystem -eq 'AppVeyor') - { - [xml]$content = Get-Content $TestFilePath - $content.'test-results'.'test-suite'.type = "Powershell" - $content.Save($TestFilePath) + [xml]$content = Get-Content $TestFilePath + $content.'test-results'.'test-suite'.type = "Powershell" + $content.Save($TestFilePath) + # In Appveyor? Upload our tests! #Abstract this into a function? + If($ENV:BHBuildSystem -eq 'AppVeyor') { "Uploading $ProjectRoot\$TestFile to AppVeyor" "JobID: $env:APPVEYOR_JOB_ID" (New-Object 'System.Net.WebClient').UploadFile("https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path $TestFilePath)) @@ -79,8 +74,7 @@ Task Test -Depends UnitTests { # Failed tests? # Need to tell psake or it will proceed to the deployment. Danger! - if($TestResults.FailedCount -gt 0) - { + if($TestResults.FailedCount -gt 0) { Write-Error "Failed '$($TestResults.FailedCount)' tests, build failed" } "`n" @@ -89,9 +83,9 @@ Task Test -Depends UnitTests { Task Build -Depends Test { $lines - $functions = Get-ChildItem "$ENV:BHModulePath\Public\*.ps1" | - Where-Object{ $_.name -notmatch 'Tests'} | - Select-Object -ExpandProperty basename + $functions = Get-ChildItem "$ENV:BHModulePath\Public\*.ps1" | + Where-Object {$_.name -notmatch 'Tests'} | + Select-Object -ExpandProperty basename # Load the module, read the exported functions, update the psd1 FunctionsToExport Set-ModuleFunctions -Name $env:BHPSModuleManifest -FunctionsToExport $functions @@ -105,11 +99,11 @@ Task Build -Depends Test { } $Script:version = [version]::New($version.Major,$version.Minor,$version.Build) Write-Host "Using version: $version" - + Update-Metadata -Path $env:BHPSModuleManifest -PropertyName ModuleVersion -Value $version # Update Code Coverage - Function Update-CodeCoveragePercent{ + Function Update-CodeCoveragePercent { param( [int]$CodeCoverage=0, [string]$TextFilePath="$Env:BHProjectPath\Readme.md" @@ -138,16 +132,15 @@ Task Build -Depends Test { Task MakePackage -Depends Build,Test { $lines - function ZipFiles - { + function ZipFiles { param( $zipfilename, $sourcedir ) - Add-Type -Assembly System.IO.Compression.FileSystem + Add-Type -Assembly System.IO.Compression.FileSystem $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal [System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir, - $zipfilename, $compressionLevel, $true) + $zipfilename, $compressionLevel, $true) } - function New-MakePackage{ + function New-MakePackage { param( [string]$PackageName, [string]$PackagePath, @@ -171,24 +164,21 @@ Task Deploy -Depends Build,MakePackage { $lines # Gate deployment - if( + if ( $ENV:BHBuildSystem -ne 'Unknown' -and $ENV:BHBranchName -eq "master" -and $ENV:BHCommitMessage -match '!deploy' - ) - { + ) { $Params = @{ Path = $ProjectRoot Force = $true } Invoke-PSDeploy @Verbose @Params - } - else - { + } else { "Skipping deployment: To deploy, ensure that...`n" + "`t* You are in a known build system (Current: $ENV:BHBuildSystem)`n" + "`t* You are committing to the master branch (Current: $ENV:BHBranchName) `n" + "`t* Your commit message includes !deploy (Current: $ENV:BHCommitMessage)" } -} \ No newline at end of file +} diff --git a/Readme.md b/Readme.md index 6c9ed56..a726264 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-74%25-orange.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-78%25-yellow.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. @@ -77,9 +77,11 @@ The `Connection` parameter accepts a hashtable object that requires a username, ## Cmdlets * Get-ServiceNowChangeRequest -* Get-ServiceNowConfigurationItem +* Get-ServiceNowConfigurationIte * Get-ServiceNowIncident +* Get-ServiceNowRequest * Get-ServiceNowTable +* Get-ServiceNowTableEntry * Get-ServiceNowUser * Get-ServiceNowUserGroup * New-ServiceNowIncident @@ -91,6 +93,7 @@ The `Connection` parameter accepts a hashtable object that requires a username, * Test-ServiceNowAuthIsSet * Update-ServiceNowChangeRequest * Update-ServiceNowIncident +* Update-ServiceNowNumber * Update-ServiceNowTableEntry ## Tests diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index a375b10..e30f495 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -3,25 +3,27 @@ $moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") $moduleName = Split-Path $moduleRoot -Leaf $DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.json" -# Load defaults from file (merging into $global:ServiceNowPesterTestDefaults) -if(Test-Path $DefaultsFile){ - $defaults = @{} +# Load defaults from file +if (Test-Path $DefaultsFile) { + $Defaults = @{} # Add properties to the defaults hash (Get-Content $DefaultsFile | Out-String | ConvertFrom-Json).psobject.properties | ForEach-Object { - $defaults."$($_.Name)" = $_.Value + $Defaults."$($_.Name)" = $_.Value } # Prompt for credentials - $defaults.Creds = if($defaults.Creds){$defaults.Creds}else{Get-Credential} - - $global:ServiceNowPesterTestDefaults = $defaults -}else{ + $Defaults.Creds = if ($Defaults.Creds) { + $Defaults.Creds + } else { + Get-Credential + } +} else { # Write example file @{ ServiceNowURL = 'testingurl.service-now.com' - TestCategory = 'Internal' + TestCategory = 'Internal' TestUserGroup = 'e9e9a2406f4c35001855fa0dba3ee4f3' - TestUser = "7a4b573a6f3725001855fa0dba3ee485" + TestUser = "7a4b573a6f3725001855fa0dba3ee485" } | ConvertTo-Json | Set-Content $DefaultsFile Write-Error "$DefaultsFile does not exist. Created example file. Please populate with your values" Return @@ -32,22 +34,68 @@ Remove-Module $ModuleName -ErrorAction SilentlyContinue Import-Module (Join-Path $moduleRoot "$moduleName.psd1") -Force Describe "ServiceNow-Module" { + # Ensure auth is not set (not a test) If (Test-ServiceNowAuthisSet) { - Remove-ServiceNowAuth | Should -Be $True + Remove-ServiceNowAuth } + # Auth Functions It "Test-ServiceNowAuthIsSet not set" { Test-ServiceNowAuthIsSet | Should -Be $false } It "Set-ServiceNowAuth works" { - Set-ServiceNowAuth -url $defaults.ServiceNowURL -Credentials $defaults.Creds | Should -Be $true + Set-ServiceNowAuth -url $Defaults.ServiceNowURL -Credentials $Defaults.Creds | Should -Be $true } It "Test-ServiceNowAuthIsSet set" { Test-ServiceNowAuthIsSet | Should -Be $true } + # Get Functions + It "Get-ServiceNowTable returns records" { + ([array](Get-ServiceNowTable -Table 'incident' -Query 'ORDERBYDESCopened_at')).Count -gt 0 | Should -Match $true + } + + It "Get-ServiceNowTable with SpecifyConnectionFields param set returns records" { + $getServiceNowTableSplat = @{ + Table = 'incident' + Query = 'ORDERBYDESCopened_at' + ServiceNowCredential = $Defaults.Creds + ServiceNowURL = $Defaults.ServiceNowURL + } + ([array](Get-ServiceNowTable @getServiceNowTableSplat)).Count -gt 0 | Should -Match $true + } + + It "Get-ServiceNowTableEntry returns records" { + ([array](Get-ServiceNowTableEntry -Table incident)).count -gt 0 | Should -Match $true + } + + It "Get-ServiceNowIncident returns records" { + ([array](Get-ServiceNowIncident)).count -gt 0 | Should -Match $true + } + + It "Get-ServiceNowRequest returns records" { + ([array](Get-ServiceNowRequest)).count -gt 0 | Should -Match $true + } + + It "Get-ServiceNowUserGroup works" { + (Get-ServiceNowUserGroup).Count -gt 0 | Should -Match $true + } + + It "Get-ServiceNowUser works" { + (Get-ServiceNowUser).Count -gt 0 | Should -Match $true + } + + It "Get-ServiceNowConfigurationItem works" { + (Get-ServiceNowConfigurationItem).Count -gt 0 | Should -Match $true + } + + It "Get-ServiceNowChangeRequest works" { + (Get-ServiceNowChangeRequest).Count -gt 0 | Should -Match $true + } + + # New Functions It "New-ServiceNowIncident (and by extension New-ServiceNowTableEntry) works" { $ShortDescription = "Testing Ticket Creation with Pester" $newServiceNowIncidentSplat = @{ @@ -65,19 +113,32 @@ Describe "ServiceNow-Module" { $TestTicket.short_description | Should -Be $ShortDescription } - It "Get-ServiceNowTable works" { - # There should be one or more incidents returned - ([array](Get-ServiceNowTable -Table 'incident' -Query 'ORDERBYDESCopened_at')).Count -gt 0 | Should -Match $true - } + # Update functions + It "Update-ServiceNowChangeRequest works" { + $TestTicket = Get-ServiceNowChangeRequest -Limit 1 - It "Get-ServiceNowIncident works" { - # There should be one or more incidents returned - ([array](Get-ServiceNowIncident)).count -gt 0 | Should -Match $true - } + $Values = @{ + description = 'Pester Comment: Update-ServiceNowChangeRequest works' + } + + $updateServiceNowNumberSplat = @{ + SysID = $TestTicket.sys_id + Values = $Values + } + $UpdatedTicket = Update-ServiceNowChangeRequest @updateServiceNowNumberSplat + + $UpdatedTicket.description | Should -Be 'Pester Comment: Update-ServiceNowChangeRequest works' + + $Values = @{ + description = $TestTicket.description + } + + $updateServiceNowNumberSplat = @{ + SysID = $TestTicket.sys_id + Values = $Values + } + $null = Update-ServiceNowChangeRequest @updateServiceNowNumberSplat - It "Get-ServiceNowRequest works" { - # There should be one or more incidents returned - ([array](Get-ServiceNowRequest)).count -gt 0 | Should -Match $true } It "Update-ServiceNowIncident works" { @@ -91,42 +152,70 @@ Describe "ServiceNow-Module" { Category = $Defaults.TestCategory SubCategory = $Defaults.TestSubcategory ConfigurationItem = $Defaults.TestConfigurationItem - } $TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat $TestTicket.short_description | Should -Be $ShortDescription - $Values = - @{ + $Values = @{ 'short_description' = 'Ticket Updated with Pester' 'description' = 'Even Longer Description' } - Update-ServiceNowIncident -SysId $TestTicket.sys_id -Values $Values + $null = 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 - } + It "Update-ServiceNowNumber works" { + $ShortDescription = "Testing Ticket Update with Pester" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = "Long description" + AssignmentGroup = $Defaults.TestUserGroup + Comment = "Comment" + Category = $Defaults.TestCategory + SubCategory = $Defaults.TestSubcategory + ConfigurationItem = $Defaults.TestConfigurationItem + } + $TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat - It "Get-ServiceNowUser works" { - # There should be one or more user groups returned - (Get-ServiceNowUser).Count -gt 0 | Should -Match $true - } + $TestTicket.short_description | Should -Be $ShortDescription - It "Get-ServiceNowConfigurationItem works" { - # There should be one or more configuration items returned - (Get-ServiceNowConfigurationItem).Count -gt 0 | Should -Match $true + $Values = @{ + 'short_description' = 'Ticket Updated with Pester (Update-ServiceNowNumber)' + 'description' = 'Updated by Pester test Update-ServiceNowNumber works' + } + + $updateServiceNowNumberSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + Values = $Values + } + Update-ServiceNowNumber @updateServiceNowNumberSplat + + $TestTicket = Get-ServiceNowIncident -MatchExact @{sys_id=$TestTicket.sys_id} + $TestTicket.short_description | Should -Be 'Ticket Updated with Pester (Update-ServiceNowNumber)' + $TestTicket.description | Should -Be 'Updated by Pester test Update-ServiceNowNumber works' } - It "Get-ServiceNowChangeRequest works" { - (Get-ServiceNowChangeRequest).Count -gt 0 | Should -Match $true + # Remove Functions + It "Remove-ServiceNowTable works" { + $TestTicket = Get-ServiceNowIncident -Limit 1 + $removeServiceNowTableEntrySplat = @{ + SysId = $TestTicket.sys_id + Table = 'incident' + } + Remove-ServiceNowTableEntry @removeServiceNowTableEntrySplat + + $getServiceNowIncidentSplat = @{ + MatchExact = @{sys_id=$($Ticket.sys_id)} + ErrorAction = 'Stop' + } + {Get-ServiceNowIncident @getServiceNowIncidentSplat} | Should -Throw '(404) Not Found' } It "Remove-ServiceNowAuth works" { From 7781d80abca5a995f4b624f49b314e87e58f5470 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 5 Oct 2018 12:58:58 -0500 Subject: [PATCH 098/348] Bug fix in Update-ServiceNowNumber. Added Pester Test. --- ServiceNow/Public/Update-ServiceNowNumber.ps1 | 9 ++--- Tests/ServiceNow.Tests.ps1 | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 index 14fa245..c0ee71a 100644 --- a/ServiceNow/Public/Update-ServiceNowNumber.ps1 +++ b/ServiceNow/Public/Update-ServiceNowNumber.ps1 @@ -70,15 +70,15 @@ Function Update-ServiceNowNumber { # Process credential steps based on parameter set name Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { + $getServiceNowTableEntry.Add('ServiceNowCredential',$Credential) + $getServiceNowTableEntry.Add('ServiceNowURL',$ServiceNowURL) $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' - $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) - $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) } 'UseConnectionObject' { + $getServiceNowTableEntry.Add('Connection',$Connection) $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' - $updateServiceNowTableEntrySplat.Add('Connection',$Connection) } Default { If ((Test-ServiceNowAuthIsSet)) { @@ -90,9 +90,10 @@ Function Update-ServiceNowNumber { } } } - + Write-Verbose "ServiceNowURL: $ServiceNowURL" # Use the number and table to determine the sys_id $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + Write-Verbose "SysID: $SysID" # Convert the values to Json and encode them to an UTF8 array to support special chars $Body = $Values | ConvertTo-Json diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index e30f495..ea18a8c 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -202,6 +202,41 @@ Describe "ServiceNow-Module" { $TestTicket.description | Should -Be 'Updated by Pester test Update-ServiceNowNumber works' } + It "Update-ServiceNowNumber with SpecifyConnectionFields works" { + $ShortDescription = 'Testing Ticket Update with Pester' + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + AssignmentGroup = $Defaults.TestUserGroup + Comment = 'Comment' + Category = $Defaults.TestCategory + SubCategory = $Defaults.TestSubcategory + ConfigurationItem = $Defaults.TestConfigurationItem + } + $TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should -Be $ShortDescription + + $Values = @{ + 'short_description' = 'Ticket Updated with Pester (Update-ServiceNowNumber)' + 'description' = 'Updated by Pester test Update-ServiceNowNumber with SpecifyConnectionFields works' + } + + $updateServiceNowNumberSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + Values = $Values + Credential = $Defaults.Creds + ServiceNowURL = $Defaults.ServiceNowURL + } + Update-ServiceNowNumber @updateServiceNowNumberSplat + + $TestTicket = Get-ServiceNowIncident -MatchExact @{sys_id=$TestTicket.sys_id} + $TestTicket.short_description | Should -Be 'Ticket Updated with Pester (Update-ServiceNowNumber)' + $TestTicket.description | Should -Be 'Updated by Pester test Update-ServiceNowNumber with SpecifyConnectionFields works' + } + # Remove Functions It "Remove-ServiceNowTable works" { $TestTicket = Get-ServiceNowIncident -Limit 1 From be4d9463647f30fbb160d6a640979b90bff1e335 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 5 Oct 2018 13:10:36 -0500 Subject: [PATCH 099/348] v1.2.2 - Bug fix for Update-ServiceNowNumber --- Readme.md | 2 +- ServiceNow/ServiceNow.psd1 | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index a726264..737753c 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-78%25-yellow.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-80%25-yellow.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. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index da540c3..b968c29 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.2.1' +ModuleVersion = '1.2.2' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -103,3 +103,5 @@ PrivateData = @{ + + From 3886b20c68c174729c45db33ad45578c95202f8d Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 5 Oct 2018 13:12:53 -0500 Subject: [PATCH 100/348] Removed verbose messages used in testing --- ServiceNow/Public/Update-ServiceNowNumber.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 index c0ee71a..e4d35af 100644 --- a/ServiceNow/Public/Update-ServiceNowNumber.ps1 +++ b/ServiceNow/Public/Update-ServiceNowNumber.ps1 @@ -90,10 +90,9 @@ Function Update-ServiceNowNumber { } } } - Write-Verbose "ServiceNowURL: $ServiceNowURL" + # Use the number and table to determine the sys_id $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id - Write-Verbose "SysID: $SysID" # Convert the values to Json and encode them to an UTF8 array to support special chars $Body = $Values | ConvertTo-Json From b7179babacd0611b8041814fedb49b299f208304 Mon Sep 17 00:00:00 2001 From: Aiden Vaines Date: Tue, 9 Oct 2018 12:21:05 +0100 Subject: [PATCH 101/348] Adding Example for New-ServiceNowIncident Adding Example for New-ServiceNowIncident because it took me far longer to workout how to do this than I would like to admit. I'm sure others will run in to the same at some point. --- Readme.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Readme.md b/Readme.md index 737753c..f410f80 100644 --- a/Readme.md +++ b/Readme.md @@ -68,6 +68,18 @@ $Incident = Get-ServiceNowIncident -Limit 1 -MatchContains @{short_description=' Update-ServiceNowIncident -SysID $Incident.Sys_ID -Values @{comments='Updated via PowerShell'} ``` +### Example - Creating a Incident with custom table entries + +```PowerShell +$IncidentParams = @{Caller = "UserName" + ShortDescription = "New PS Incident" + Description = "This incident was created from Powershell" + CustomFields = @{u_service = "MyService" + u_incident_type = "Request"} + } +New-ServiceNowIncident @Params +``` + ### Azure Connection Object (Automation Integration Module Support) The module can use the `Connection` parameter in conjunction with the included `ServiceNow-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). From 72d1b14616c36051080e8ca49440ce82395bba5e Mon Sep 17 00:00:00 2001 From: Aiden Vaines Date: Fri, 12 Oct 2018 09:36:34 +0100 Subject: [PATCH 102/348] Adding comment based help to function I've added comment based help to this function as requested under Pull/55 Both: Get-Help New-ServiceNowIncident Get-Help New-ServiceNowIncident -examples Will show relevant help sections --- ServiceNow/Public/New-ServiceNowIncident.ps1 | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 1e6a3aa..449f18c 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -1,4 +1,36 @@ function New-ServiceNowIncident{ +<# +.SYNOPSIS + Generates a new ServiceNow Incident + +.DESCRIPTION + Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API + +.LINK + https://github.com/Sam-Martin/servicenow-powershell + +.EXAMPLE + Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. + New-ServiceNowIncident -Caller "UserName" -ShortDescription = "New PS Incident" -Description = "This incident was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 + +.EXAMPLE + Generate an Incident by "Splatting" all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow Instance): + + $IncidentParams = @{Caller = "UserName" + ShortDescription = "New PS Incident" + Description = "This incident was created from Powershell" + AssignmentGroup "ServiceDesk" + Comment "Inline Comment" + Category "Office" + Subcategory "Outlook" + ConfigurationItem UserPC1 + CustomFields = @{u_custom1 = "Custom Field Entry" + u_another_custom = "Related Test"} + } + New-ServiceNowIncident @Params + + #> + Param( # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) From 4559599109db6dbf0a770f986c5ea9e662180a63 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 12 Oct 2018 13:04:20 -0500 Subject: [PATCH 103/348] Advance version to 1.2.3 for CBH addition. Unreleased version. --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index b968c29..70c1ef5 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.2.2' +ModuleVersion = '1.2.3' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 44b6f7c5ed216bfd0691ba345b2ba106fb3c8be1 Mon Sep 17 00:00:00 2001 From: Brownstein Date: Fri, 12 Oct 2018 15:42:36 -0400 Subject: [PATCH 104/348] set key names to lowercase --- ServiceNow/Public/New-ServiceNowQuery.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index 66e4ca8..809799f 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -4,12 +4,12 @@ function New-ServiceNowQuery{ # Machine name of the field to order by [parameter(mandatory=$false)] [string]$OrderBy='opened_at', - + # Direction of ordering (Desc/Asc) [parameter(mandatory=$false)] [ValidateSet("Desc", "Asc")] [string]$OrderDirection='Desc', - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory=$false)] [hashtable]$MatchExact, @@ -30,14 +30,14 @@ function New-ServiceNowQuery{ # Build the exact matches into the query if($MatchExact){ foreach($Field in $MatchExact.keys){ - $Query += "^$Field="+$MatchExact.$Field + $Query += "^{0}={1}" -f $Field.ToString().ToLower(), ($MatchExact.$Field) } } # Add the values which given fields should contain if($MatchContains){ foreach($Field in $MatchContains.keys){ - $Query += "^$($Field)LIKE"+$MatchContains.$Field + $Query += "^{0}LIKE{1}" -f $Field.ToString().ToLower(), ($MatchContains.$Field) } } From 30ad7e6df7b23cff9d8b96113aa0d65c3c6d3ba3 Mon Sep 17 00:00:00 2001 From: Brownstein Date: Fri, 12 Oct 2018 16:46:56 -0400 Subject: [PATCH 105/348] move string query generation to private --- .../New-ServiceNowQuery.ps1 | 19 +++++++++++++++++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) rename ServiceNow/{Public => Private}/New-ServiceNowQuery.ps1 (75%) diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Private/New-ServiceNowQuery.ps1 similarity index 75% rename from ServiceNow/Public/New-ServiceNowQuery.ps1 rename to ServiceNow/Private/New-ServiceNowQuery.ps1 index 809799f..a0a97e7 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Private/New-ServiceNowQuery.ps1 @@ -1,5 +1,24 @@ +<# +.SYNOPSIS + Build query string for api call +.DESCRIPTION + Build query string for api call +.EXAMPLE + New-ServiceNowQuery -MatchExact @{field_name=value} + Get query string where field name exactly matches the value +.EXAMPLE + New-ServiceNowQuery -MatchContains @{field_name=value} + Get query string where field name contains the value +.INPUTS + None +.OUTPUTS + String +#> function New-ServiceNowQuery{ + [CmdletBinding()] + [OutputType([System.String])] + param( # Machine name of the field to order by [parameter(mandatory=$false)] diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index da540c3..fd3338e 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From 361bcc3a76150d5b0665c7d15a47e47d12fe2da8 Mon Sep 17 00:00:00 2001 From: Brownstein Date: Thu, 18 Oct 2018 10:35:56 -0400 Subject: [PATCH 106/348] move new-servicenowquery back to public for now --- ServiceNow/{Private => Public}/New-ServiceNowQuery.ps1 | 0 ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename ServiceNow/{Private => Public}/New-ServiceNowQuery.ps1 (100%) diff --git a/ServiceNow/Private/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 similarity index 100% rename from ServiceNow/Private/New-ServiceNowQuery.ps1 rename to ServiceNow/Public/New-ServiceNowQuery.ps1 diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index fd3338e..da540c3 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From f937bc9a2bd8cc00223872f23d870aa2efa818e4 Mon Sep 17 00:00:00 2001 From: Wayne Hoggett Date: Thu, 8 Nov 2018 08:29:03 +1000 Subject: [PATCH 107/348] Minor comment change --- ServiceNow/Public/Update-ServiceNowTableEntry.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 index c202643..4e823ed 100644 --- a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 @@ -1,14 +1,14 @@ function Update-ServiceNowTableEntry{ [CmdletBinding(ConfirmImpact='High')] Param( - # sys_id of the entry we're deleting + # sys_id of the entry we're updating [parameter(mandatory=$true)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$SysId, - # Table containing the entry we're deleting + # Table containing the entry we're updating [parameter(mandatory=$true)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] From 0506b28cc0996a417775cd88af9d328660175607 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 6 Dec 2018 13:41:18 -0600 Subject: [PATCH 108/348] Tweaks/Code Cleanup of New-ServiceNowQuery --- ServiceNow/Public/New-ServiceNowQuery.ps1 | 88 +++++++++++++---------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index a0a97e7..d18417a 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -1,20 +1,25 @@ -<# -.SYNOPSIS - Build query string for api call -.DESCRIPTION - Build query string for api call -.EXAMPLE - New-ServiceNowQuery -MatchExact @{field_name=value} - Get query string where field name exactly matches the value -.EXAMPLE - New-ServiceNowQuery -MatchContains @{field_name=value} - Get query string where field name contains the value -.INPUTS - None -.OUTPUTS - String -#> -function New-ServiceNowQuery{ +function New-ServiceNowQuery { + <# + .SYNOPSIS + Build query string for api call + .DESCRIPTION + Build query string for api call + .EXAMPLE + New-ServiceNowQuery -MatchExact @{field_name=value} + + Get query string where field name exactly matches the value + .EXAMPLE + New-ServiceNowQuery -MatchContains @{field_name=value} + + Get query string where field name contains the value + .INPUTS + None + .OUTPUTS + String + #> + + # This function doesn't change state. Doesn't justify ShouldProcess functionality + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions','')] [CmdletBinding()] [OutputType([System.String])] @@ -37,28 +42,39 @@ function New-ServiceNowQuery{ [parameter(mandatory=$false)] [hashtable]$MatchContains ) - # Start the query off with a order direction - $Query = ''; - if($OrderDirection -eq 'Asc'){ - $Query += 'ORDERBY' - }else{ - $Query += 'ORDERBYDESC' - } - $Query +="$OrderBy" - # Build the exact matches into the query - if($MatchExact){ - foreach($Field in $MatchExact.keys){ - $Query += "^{0}={1}" -f $Field.ToString().ToLower(), ($MatchExact.$Field) + Try { + # Create StringBuilder + $Query = New-Object System.Text.StringBuilder + + # Start the query off with a order direction + $Order = Switch ($OrderDirection) { + 'Asc' {'ORDERBY'} + Default {'ORDERBYDESC'} } - } + [void]$Query.Append($Order) - # Add the values which given fields should contain - if($MatchContains){ - foreach($Field in $MatchContains.keys){ - $Query += "^{0}LIKE{1}" -f $Field.ToString().ToLower(), ($MatchContains.$Field) + # Build the exact matches into the query + If ($MatchExact) { + $Match = ForEach ($Field in $MatchExact.keys) { + "^{0}={1}" -f $Field.ToString().ToLower(), ($MatchExact.$Field) + } + } + + # Add the values which given fields should contain + If ($MatchContains) { + $Match = ForEach ($Field in $MatchContains.keys) { + "^{0}LIKE{1}" -f $Field.ToString().ToLower(), ($MatchContains.$Field) + } } - } - return $Query + # Append Match (Exact or Contains) + [void]$Query.Append($Match) + + # Output StringBuilder to string + $Query.ToString() + } + Catch { + Write-Error $PSItem + } } From c0f2018921a2e34418f42951d16668ac30298965 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 6 Dec 2018 15:06:48 -0600 Subject: [PATCH 109/348] Fixed misses in tweak/cleanup. --- ServiceNow/Public/New-ServiceNowQuery.ps1 | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index d18417a..4e3627e 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -54,23 +54,25 @@ function New-ServiceNowQuery { } [void]$Query.Append($Order) + # Add OrderBy + [void]$Query.Append($OrderBy) + # Build the exact matches into the query If ($MatchExact) { - $Match = ForEach ($Field in $MatchExact.keys) { - "^{0}={1}" -f $Field.ToString().ToLower(), ($MatchExact.$Field) + ForEach ($Field in $MatchExact.keys) { + $ExactString = "^{0}={1}" -f $Field.ToString().ToLower(), ($MatchExact.$Field) + [void]$Query.Append($ExactString) } } # Add the values which given fields should contain If ($MatchContains) { - $Match = ForEach ($Field in $MatchContains.keys) { - "^{0}LIKE{1}" -f $Field.ToString().ToLower(), ($MatchContains.$Field) + ForEach ($Field in $MatchContains.keys) { + $ContainsString = "^{0}LIKE{1}" -f $Field.ToString().ToLower(), ($MatchContains.$Field) + [void]$Query.Append($ContainsString) } } - # Append Match (Exact or Contains) - [void]$Query.Append($Match) - # Output StringBuilder to string $Query.ToString() } From 643b3efb021d737c881948ef74e45f95fdd7ccf9 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 6 Dec 2018 15:20:50 -0600 Subject: [PATCH 110/348] Advance version to 1.2.4 --- Readme.md | 6 +++--- ServiceNow/ServiceNow.psd1 | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index f410f80..bac1daa 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-80%25-yellow.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-79%25-yellow.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. @@ -44,7 +44,7 @@ Once you've done this, all the cmdlets will be at your disposal, you can see a f Set-ServiceNowAuth -url InstanceName.service-now.com -Credentials (Get-Credential) ``` -The URL should be the instance name portion of the FQDN for your instance. For if you browse to `https://yourinstance.service-now.com` the URL required for the module is `yourinstance.service-now.com`. +The URL should be the instance name portion of the FQDN for your instance. If you browse to `https://yourinstance.service-now.com` the URL required for the module is `yourinstance.service-now.com`. ### Example - Retrieving an Incident Containing the Word 'PowerShell' @@ -76,7 +76,7 @@ $IncidentParams = @{Caller = "UserName" Description = "This incident was created from Powershell" CustomFields = @{u_service = "MyService" u_incident_type = "Request"} - } + } New-ServiceNowIncident @Params ``` diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 70c1ef5..b5f22b5 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.2.3' +ModuleVersion = '1.2.4' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -105,3 +105,5 @@ PrivateData = @{ + + From 1e2287aefaddf41438be19016bfd3d983bec9bff Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 7 Dec 2018 12:02:24 -0600 Subject: [PATCH 111/348] Added notes on SNow permissions under reqs --- Readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Readme.md b/Readme.md index bac1daa..6545d4a 100644 --- a/Readme.md +++ b/Readme.md @@ -32,6 +32,12 @@ These changes should improve your ability to filter on the right, especially by Requires PowerShell 3.0 or above as this is when `Invoke-RestMethod` was introduced. +Requires authorization in your ServiceNow tenant. Due to the custom nature of ServiceNow your organization may have REST access restricted. The following are some tips to ask for if you're having to go to your admin for access: + +* Out of the box tables should be accessible by granting the `ITIL` role. +* Custom tables may require adjustments to the ACL. +* The `Web_Service_Admin` role may also be an option. + ## Usage Download the [latest release](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: From 30991c04c749f22b4aaa874ad559b44fffe86474 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 17 Dec 2018 11:27:50 -0600 Subject: [PATCH 112/348] Create function Get-ServiceNowRequestItem This function is copied from the Get-ServiceNowRequest function. The only real difference is the table it queries. I copied and pasted a simple test for this function from the Get-ServiceNowRequest function, but I can't access the test environment it's querying in order to validate that the test works. --- .../Public/Get-ServiceNowRequestItem.ps1 | 93 +++++++++++++++++++ ServiceNow/ServiceNow.psd1 | 2 +- Tests/ServiceNow.Tests.ps1 | 4 + 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 ServiceNow/Public/Get-ServiceNowRequestItem.ps1 diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 new file mode 100644 index 0000000..da28683 --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -0,0 +1,93 @@ +function Get-ServiceNowRequestItem { + param( + # Machine name of the field to order by + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string]$OrderBy = 'opened_at', + + # Direction of ordering (Desc/Asc) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [ValidateSet("Desc", "Asc")] + [string]$OrderDirection = 'Desc', + + # Maximum number of records to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [int]$Limit = 10, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [hashtable]$MatchExact = @{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [hashtable]$MatchContains = @{}, + + # Whether or not to show human readable display values instead of machine values + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [ValidateSet("true", "false", "all")] + [string]$DisplayValues = 'true', + + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [PSCredential] + $ServiceNowCredential, + + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [string] + $ServiceNowURL, + + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [ValidateNotNullOrEmpty()] + [Hashtable] + $Connection + ) + + # Query Splat + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + MatchExact = $MatchExact + OrderDirection = $OrderDirection + MatchContains = $MatchContains + } + $Query = New-ServiceNowQuery @newServiceNowQuerySplat + + # Table Splat + $getServiceNowTableSplat = @{ + Table = 'sc_req_item' + Query = $Query + Limit = $Limit + DisplayValues = $DisplayValues + } + + # Update the Table Splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) { + $getServiceNowTableSplat.Add('Connection', $Connection) + } + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) + } + + # Perform query and return each object in the format.ps1xml format + $Result = Get-ServiceNowTable @getServiceNowTableSplat + $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0, "ServiceNow.Request")} + $Result +} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index b5f22b5..d7a2279 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index ea18a8c..42b04fe 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -79,6 +79,10 @@ Describe "ServiceNow-Module" { ([array](Get-ServiceNowRequest)).count -gt 0 | Should -Match $true } + It "Get-ServiceNowRequestItem returns records" { + ([array](Get-ServiceNowRequestItem)).count -gt 0 | Should -Match $true + } + It "Get-ServiceNowUserGroup works" { (Get-ServiceNowUserGroup).Count -gt 0 | Should -Match $true } From d0f05b219f86856655d156559caa5d410f9bfa76 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 17 Dec 2018 12:05:32 -0600 Subject: [PATCH 113/348] Fix type name (copy/paste error) --- ServiceNow/Public/Get-ServiceNowRequestItem.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index da28683..227a5f5 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -88,6 +88,6 @@ function Get-ServiceNowRequestItem { # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0, "ServiceNow.Request")} + $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0, "ServiceNow.RequestItem")} $Result } From 39823cf102fa3a0a33b4a020b9f11649f32740a5 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 17 Dec 2018 12:50:23 -0600 Subject: [PATCH 114/348] Add -Fields param to Get-ServiceNowTable --- ServiceNow/Public/Get-ServiceNowTable.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 36f7289..0a5ac66 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -35,6 +35,13 @@ function Get-ServiceNowTable { [parameter(ParameterSetName = 'SetGlobalAuth')] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string[]]$Fields, + # Whether or not to show human readable display values instead of machine values [parameter(ParameterSetName = 'SpecifyConnectionFields')] [parameter(ParameterSetName = 'UseConnectionObject')] @@ -84,6 +91,10 @@ function Get-ServiceNowTable { $Body.sysparm_query = $Query } + if ($Fields) { + $Body.sysparm_fields = $Fields -join ',' + } + # Perform table query and capture results $Uri = $ServiceNowURL + "/table/$Table" $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result From 51f949f6d0d7e320798616dfa4be1a6ce33c2e0d Mon Sep 17 00:00:00 2001 From: Joshua T Date: Mon, 17 Dec 2018 14:07:50 -0600 Subject: [PATCH 115/348] Add -Fields parameter to wrappers --- .../Public/Get-ServiceNowChangeRequest.ps1 | 7 ++++++ .../Get-ServiceNowConfigurationItem.ps1 | 7 ++++++ ServiceNow/Public/Get-ServiceNowIncident.ps1 | 7 ++++++ ServiceNow/Public/Get-ServiceNowRequest.ps1 | 23 ++++++++++++------- .../Public/Get-ServiceNowRequestItem.ps1 | 8 +++++++ 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index c49c1d3..2d7210e 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -1,5 +1,12 @@ function Get-ServiceNowChangeRequest { param( + # Fields to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string[]]$Fields, + # Machine name of the field to order by [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 34cb727..ef6804f 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -1,5 +1,12 @@ function Get-ServiceNowConfigurationItem { param( + # Fields to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string[]]$Fields, + # Machine name of the field to order by [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 993c0c8..f23c15e 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -1,5 +1,12 @@ function Get-ServiceNowIncident{ param( + # Fields to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string[]]$Fields, + # Machine name of the field to order by [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index d59520d..1ef98b7 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -1,12 +1,19 @@ function Get-ServiceNowRequest { param( + # Fields to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string[]]$Fields, + # Machine name of the field to order by [parameter(mandatory = $false)] [parameter(ParameterSetName = 'SpecifyConnectionFields')] [parameter(ParameterSetName = 'UseConnectionObject')] [parameter(ParameterSetName = 'SetGlobalAuth')] [string]$OrderBy = 'opened_at', - + # Direction of ordering (Desc/Asc) [parameter(mandatory = $false)] [parameter(ParameterSetName = 'SpecifyConnectionFields')] @@ -21,7 +28,7 @@ function Get-ServiceNowRequest { [parameter(ParameterSetName = 'UseConnectionObject')] [parameter(ParameterSetName = 'SetGlobalAuth')] [int]$Limit = 10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(mandatory = $false)] [parameter(ParameterSetName = 'SpecifyConnectionFields')] @@ -47,19 +54,19 @@ function Get-ServiceNowRequest { [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] [PSCredential] - $ServiceNowCredential, + $ServiceNowCredential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection ) - + # Query Splat $newServiceNowQuerySplat = @{ OrderBy = $OrderBy @@ -68,7 +75,7 @@ function Get-ServiceNowRequest { MatchContains = $MatchContains } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - + # Table Splat $getServiceNowTableSplat = @{ Table = 'sc_request' @@ -78,7 +85,7 @@ function Get-ServiceNowRequest { } # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { + if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index 227a5f5..953dcdd 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -1,5 +1,12 @@ function Get-ServiceNowRequestItem { param( + # Fields to return + [parameter(mandatory = $false)] + [parameter(ParameterSetName = 'SpecifyConnectionFields')] + [parameter(ParameterSetName = 'UseConnectionObject')] + [parameter(ParameterSetName = 'SetGlobalAuth')] + [string[]]$Fields, + # Machine name of the field to order by [parameter(mandatory = $false)] [parameter(ParameterSetName = 'SpecifyConnectionFields')] @@ -74,6 +81,7 @@ function Get-ServiceNowRequestItem { Table = 'sc_req_item' Query = $Query Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues } From 2c6b836f0fe44cbe051e3fa8a8bad557ed65f732 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 27 Dec 2018 15:07:09 -0600 Subject: [PATCH 116/348] Added help, used lean params, set format to existing option --- .../Public/Get-ServiceNowRequestItem.ps1 | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index 227a5f5..fdb929a 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -1,63 +1,61 @@ function Get-ServiceNowRequestItem { +<# + .SYNOPSIS + Query for Request Item (RITM) tickets. + + .DESCRIPTION + Query for Request Item (RITM) tickets from the sc_req_item table. + + .EXAMPLE + Get-ServiceNowRequestItem -MatchExact @{number='RITM0000001'} + + Return the details for RITM0000001 + + .OUTPUTS + System.Management.Automation.PSCustomObject +#> + + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName)] param( # Machine name of the field to order by - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [parameter(Mandatory = $false)] [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] + [parameter(Mandatory = $false)] + [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [parameter(Mandatory = $false)] [int]$Limit = 10, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [parameter(Mandatory = $false)] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] - [ValidateSet("true", "false", "all")] + [parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [string]$ServiceNowURL, [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) # Query Splat @@ -88,6 +86,6 @@ function Get-ServiceNowRequestItem { # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0, "ServiceNow.RequestItem")} + $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0,'ServiceNow.Request')} $Result } From 75ce655ef09f044f75a34279bba3c84a2190c9df Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 27 Dec 2018 15:14:37 -0600 Subject: [PATCH 117/348] v1.3.5 --- Readme.md | 2 +- ServiceNow/ServiceNow.psd1 | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 6545d4a..1327209 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-79%25-yellow.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-80%25-yellow.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. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index d7a2279..1cede23 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.2.4' +ModuleVersion = '1.3.5' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -107,3 +107,7 @@ PrivateData = @{ + + + + From 48a31adb56fad1e50dabbb4ce47b0042e8da9c06 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 27 Dec 2018 16:32:49 -0600 Subject: [PATCH 118/348] Add private folder & Test-ServiceNowURL private function --- ServiceNow/Private/Test-ServiceNowURL.ps1 | 39 +++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 ServiceNow/Private/Test-ServiceNowURL.ps1 diff --git a/ServiceNow/Private/Test-ServiceNowURL.ps1 b/ServiceNow/Private/Test-ServiceNowURL.ps1 new file mode 100644 index 0000000..55113f8 --- /dev/null +++ b/ServiceNow/Private/Test-ServiceNowURL.ps1 @@ -0,0 +1,39 @@ +Function Test-ServiceNowURL { + <# + .SYNOPSIS + For use in testing ServiceNow Urls. + + .DESCRIPTION + For use in testing ServiceNow Urls. The test is a simple regex match in an attempt to validate that users use a 'tenant.domain.com' pattern. + + .EXAMPLE + Test-ServiceNowURL -Url tenant.domain.com + + This example can have text + + .OUTPUTS + System.Boolean + + #> + + [OutputType([System.Boolean])] + [CmdletBinding()] + param ( + # Pipeline variable + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$Url + ) + + begin {} + process { + Write-Verbose "Testing url: $Url" + if ($Url -match '^\w+\..*\.\w+') { + $true + } + else { + Throw "The expected URL format is tenant.domain.com" + } + } + end {} +} From f3b47917ab101951fb06b49912354712bdfe9ac9 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 27 Dec 2018 16:33:20 -0600 Subject: [PATCH 119/348] Replace ValidateScript scriptblock with private function call --- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index 3e9bdc6..7b90983 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -21,17 +21,9 @@ function Set-ServiceNowAuth { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [ValidateScript( { - if ($_ -match '^\w+\..*\.\w+') { - $true - } - else { - Throw "The expected URL format is tenant.domain.com" - } - })] - [string] - $Url, + [ValidateScript({Test-ServiceNowURL -Url $_})] + [Alias('ServiceNowUrl')] + [string]$Url, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] From 6bbb85650f0024db05531411ccb525f74c878446 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 27 Dec 2018 16:33:44 -0600 Subject: [PATCH 120/348] Apply 'lean' parameter standardization to all Get functions --- .../Public/Get-ServiceNowChangeRequest.ps1 | 71 +++++++----------- .../Get-ServiceNowConfigurationItem.ps1 | 71 +++++++----------- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 74 +++++++------------ ServiceNow/Public/Get-ServiceNowRequest.ps1 | 67 +++++++---------- .../Public/Get-ServiceNowRequestItem.ps1 | 6 +- ServiceNow/Public/Get-ServiceNowTable.ps1 | 42 ++++------- .../Public/Get-ServiceNowTableEntry.ps1 | 27 +++---- ServiceNow/Public/Get-ServiceNowUser.ps1 | 74 +++++++------------ ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 74 +++++++------------ 9 files changed, 193 insertions(+), 313 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index c49c1d3..295b787 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -1,63 +1,46 @@ function Get-ServiceNowChangeRequest { - param( + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName)] + Param( # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='opened_at', + [Parameter(Mandatory = $false)] + [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', + [Parameter(Mandatory = $false)] + [ValidateSet('Desc', 'Asc')] + [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, + [Parameter(Mandatory = $false)] + [int]$Limit = 10, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchContains = @{}, - # Whether to return manipulated display values rather than actual database values. - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + # Whether or not to show human readable display values instead of machine values + [Parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] + [string]$DisplayValues = 'true', - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] + [Alias('Url')] + [string]$ServiceNowURL, - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) # Query Splat diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 34cb727..a1b439b 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -1,63 +1,46 @@ function Get-ServiceNowConfigurationItem { - param( + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName)] + Param( # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', + [Parameter(Mandatory = $false)] + [string]$OrderBy = 'name', # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', + [Parameter(Mandatory = $false)] + [ValidateSet('Desc', 'Asc')] + [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, + [Parameter(Mandatory = $false)] + [int]$Limit = 10, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchContains = @{}, - # Whether to return manipulated display values rather than actual database values. - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + # Whether or not to show human readable display values instead of machine values + [Parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] + [string]$DisplayValues = 'true', - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] + [Alias('Url')] + [string]$ServiceNowURL, - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) # Query Splat diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 993c0c8..3205541 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -1,66 +1,46 @@ function Get-ServiceNowIncident{ - param( + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName)] + Param( # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='opened_at', + [Parameter(Mandatory = $false)] + [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', + [Parameter(Mandatory = $false)] + [ValidateSet('Desc', 'Asc')] + [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, + [Parameter(Mandatory = $false)] + [int]$Limit = 10, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchContains = @{}, - # Whether to return manipulated display values rather than actual database values. - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + # Whether or not to show human readable display values instead of machine values + [Parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] + [string]$DisplayValues = 'true', - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] + [Alias('Url')] + [string]$ServiceNowURL, - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) # Query Splat diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index d59520d..226a5f4 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -1,65 +1,48 @@ function Get-ServiceNowRequest { - param( + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName)] + Param( # Machine name of the field to order by - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [Parameter(Mandatory = $false)] [string]$OrderBy = 'opened_at', - + # Direction of ordering (Desc/Asc) - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] + [Parameter(Mandatory = $false)] + [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [Parameter(Mandatory = $false)] [int]$Limit = 10, - + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [Parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [Parameter(Mandatory = $false)] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [parameter(mandatory = $false)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] - [ValidateSet("true", "false", "all")] + [Parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] + [Alias('Url')] + [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) - + # Query Splat $newServiceNowQuerySplat = @{ OrderBy = $OrderBy @@ -68,7 +51,7 @@ function Get-ServiceNowRequest { MatchContains = $MatchContains } $Query = New-ServiceNowQuery @newServiceNowQuerySplat - + # Table Splat $getServiceNowTableSplat = @{ Table = 'sc_request' @@ -78,7 +61,7 @@ function Get-ServiceNowRequest { } # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { + if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index fdb929a..1db7a5b 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -44,16 +44,16 @@ function Get-ServiceNowRequestItem { [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] [hashtable]$Connection ) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 36f7289..7926125 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -14,51 +14,39 @@ function Get-ServiceNowTable { #> [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName)] Param ( # Name of the table we're querying (e.g. incidents) - [parameter(Mandatory)] - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Table, # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [Parameter(Mandatory = $false)] [string]$Query, # Maximum number of records to return - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] + [Parameter(Mandatory = $false)] [int]$Limit = 10, # Whether or not to show human readable display values instead of machine values - [parameter(ParameterSetName = 'SpecifyConnectionFields')] - [parameter(ParameterSetName = 'UseConnectionObject')] - [parameter(ParameterSetName = 'SetGlobalAuth')] - [ValidateSet("true", "false", "all")] + [Parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields')] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [Alias('Url')] + [string]$ServiceNowURL, - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) # Get credential and ServiceNow REST URL @@ -68,6 +56,7 @@ function Get-ServiceNowTable { $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' } elseif ($null -ne $ServiceNowCredential -and $null -ne $ServiceNowURL) { + Test-ServiceNowURL -Url $ServiceNowURL $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' } elseif ((Test-ServiceNowAuthIsSet)) { @@ -109,6 +98,7 @@ function Get-ServiceNowTable { } Catch { # If the local culture and universal formats both fail keep the property as a string (Do nothing) + $null = 'Silencing a PSSA alert with this line' } } } diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index d0bf297..b693937 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -22,45 +22,46 @@ function Get-ServiceNowTableEntry { [CmdletBinding(DefaultParameterSetName)] param( # Table containing the entry we're deleting - [parameter(mandatory=$true)] + [parameter(mandatory = $true)] [string]$Table, # Machine name of the field to order by - [parameter(mandatory = $false)] + [parameter(Mandatory = $false)] [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [parameter(mandatory = $false)] - [ValidateSet("Desc", "Asc")] + [parameter(Mandatory = $false)] + [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(mandatory = $false)] + [parameter(Mandatory = $false)] [int]$Limit = 10, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory = $false)] + [parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory = $false)] + [parameter(Mandatory = $false)] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [parameter(mandatory = $false)] - [ValidateSet("true", "false", "all")] + [parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] - [ValidateNotNullOrEmpty()] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] + [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] [hashtable]$Connection ) diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 2c31075..c4477d5 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -1,66 +1,46 @@ function Get-ServiceNowUser{ - param( + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName)] + Param( # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', + [Parameter(Mandatory = $false)] + [string]$OrderBy = 'name', # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', + [Parameter(Mandatory = $false)] + [ValidateSet('Desc', 'Asc')] + [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, + [Parameter(Mandatory = $false)] + [int]$Limit = 10, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchContains = @{}, - # Whether to return manipulated display values rather than actual database values. - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + # Whether or not to show human readable display values instead of machine values + [Parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] + [string]$DisplayValues = 'true', - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] + [Alias('Url')] + [string]$ServiceNowURL, - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) # Query Splat diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 42af0f6..093d971 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -1,66 +1,46 @@ function Get-ServiceNowUserGroup{ - param( + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName)] + Param( # Machine name of the field to order by - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$OrderBy='name', + [Parameter(Mandatory = $false)] + [string]$OrderBy = 'name', # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', + [Parameter(Mandatory = $false)] + [ValidateSet('Desc', 'Asc')] + [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [int]$Limit=10, + [Parameter(Mandatory = $false)] + [int]$Limit = 10, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchExact=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$MatchContains=@{}, + [Parameter(Mandatory = $false)] + [hashtable]$MatchContains = @{}, - # Whether to return manipulated display values rather than actual database values. - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [ValidateSet("true","false", "all")] - [string]$DisplayValues='true', + # Whether or not to show human readable display values instead of machine values + [Parameter(Mandatory = $false)] + [ValidateSet('true', 'false', 'all')] + [string]$DisplayValues = 'true', - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] - [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] + [Alias('Url')] + [string]$ServiceNowURL, - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [hashtable]$Connection ) # Query Splat From 746f0ca300cb2a2c57babf9085fe300931d297bc Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 27 Dec 2018 16:35:18 -0600 Subject: [PATCH 121/348] v1.3.6 --- Readme.md | 2 +- ServiceNow/ServiceNow.psd1 | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 1327209..00583e3 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-80%25-yellow.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-78%25-yellow.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. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 1cede23..18ce9cf 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.3.5' +ModuleVersion = '1.3.6' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -111,3 +111,5 @@ PrivateData = @{ + + From b530d165ce28e3e05504eb86279c5b7e055d6189 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Wed, 2 Jan 2019 09:53:18 -0600 Subject: [PATCH 122/348] Fix typo in PSTypeName --- ServiceNow/Public/Get-ServiceNowRequestItem.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index 1db7a5b..6d7498e 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -86,6 +86,6 @@ function Get-ServiceNowRequestItem { # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0,'ServiceNow.Request')} + $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0,'ServiceNow.RequestItem')} $Result } From 1736ccfceeb1fc26ba59382d17bdd03960697478 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Wed, 16 Jan 2019 12:14:34 -0600 Subject: [PATCH 123/348] Add -Fields parameter to remaining Get functions --- ServiceNow/Public/Get-ServiceNowTableEntry.ps1 | 5 +++++ ServiceNow/Public/Get-ServiceNowUser.ps1 | 5 +++++ ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index b693937..4c5b132 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -38,6 +38,10 @@ function Get-ServiceNowTableEntry { [parameter(Mandatory = $false)] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [string[]]$Fields, + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, @@ -82,6 +86,7 @@ function Get-ServiceNowTableEntry { Table = $Table Query = $Query Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues ErrorAction = 'Stop' } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index c4477d5..31f5897 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -15,6 +15,10 @@ function Get-ServiceNowUser{ [Parameter(Mandatory = $false)] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [string[]]$Fields, + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, @@ -57,6 +61,7 @@ function Get-ServiceNowUser{ Table = 'sys_user' Query = $Query Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues } diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 093d971..2fa2dce 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -15,6 +15,10 @@ function Get-ServiceNowUserGroup{ [Parameter(Mandatory = $false)] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [string[]]$Fields, + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, @@ -57,6 +61,7 @@ function Get-ServiceNowUserGroup{ Table = 'sys_user_group' Query = $Query Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues } From 8e9fc9c62654cd5c6a984e4ad8704d67a6162c06 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Fri, 1 Feb 2019 09:13:03 -0600 Subject: [PATCH 124/348] Quality changes Fixed position of -Fields parameter by request. Correctly hooked up the -Fields parameter in several functions. --- ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 | 11 ++++++----- ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 | 9 +++++---- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 9 +++++---- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 9 +++++---- ServiceNow/Public/Get-ServiceNowRequestItem.ps1 | 8 ++++---- 5 files changed, 25 insertions(+), 21 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 57f43f9..5ee966e 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -2,10 +2,6 @@ function Get-ServiceNowChangeRequest { [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding(DefaultParameterSetName)] Param( - # Fields to return - [parameter(mandatory = $false)] - [string[]]$Fields, - # Machine name of the field to order by [Parameter(Mandatory = $false)] [string]$OrderBy = 'opened_at', @@ -19,6 +15,10 @@ function Get-ServiceNowChangeRequest { [Parameter(Mandatory = $false)] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [string[]]$Fields, + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, @@ -60,7 +60,8 @@ function Get-ServiceNowChangeRequest { $getServiceNowTableSplat = @{ Table = 'change_request' Query = $Query - Limit = $Limit + Limit = $ + Fields = $Fields DisplayValues = $DisplayValues } diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 7adf73c..3a5b8aa 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -2,10 +2,6 @@ function Get-ServiceNowConfigurationItem { [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding(DefaultParameterSetName)] Param( - # Fields to return - [parameter(mandatory = $false)] - [string[]]$Fields, - # Machine name of the field to order by [Parameter(Mandatory = $false)] [string]$OrderBy = 'name', @@ -19,6 +15,10 @@ function Get-ServiceNowConfigurationItem { [Parameter(Mandatory = $false)] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [string[]]$Fields, + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, @@ -61,6 +61,7 @@ function Get-ServiceNowConfigurationItem { Table = 'cmdb_ci' Query = $Query Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues } diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index b4aa7ce..d7d9403 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -2,10 +2,6 @@ function Get-ServiceNowIncident{ [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding(DefaultParameterSetName)] Param( - # Fields to return - [parameter(mandatory = $false)] - [string[]]$Fields, - # Machine name of the field to order by [Parameter(Mandatory = $false)] [string]$OrderBy = 'opened_at', @@ -19,6 +15,10 @@ function Get-ServiceNowIncident{ [Parameter(Mandatory = $false)] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [string[]]$Fields, + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, @@ -61,6 +61,7 @@ function Get-ServiceNowIncident{ Table = 'incident' Query = $Query Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues } diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index 0992c91..b458230 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -2,10 +2,6 @@ function Get-ServiceNowRequest { [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding(DefaultParameterSetName)] Param( - # Fields to return - [parameter(mandatory = $false)] - [string[]]$Fields, - # Machine name of the field to order by [Parameter(Mandatory = $false)] [string]$OrderBy = 'opened_at', @@ -19,6 +15,10 @@ function Get-ServiceNowRequest { [Parameter(Mandatory = $false)] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [string[]]$Fields, + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, @@ -61,6 +61,7 @@ function Get-ServiceNowRequest { Table = 'sc_request' Query = $Query Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues } diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index 2e8a15b..e3b002e 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -18,10 +18,6 @@ function Get-ServiceNowRequestItem { [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding(DefaultParameterSetName)] param( - # Fields to return - [parameter(mandatory = $false)] - [string[]]$Fields, - # Machine name of the field to order by [parameter(Mandatory = $false)] [string]$OrderBy = 'opened_at', @@ -35,6 +31,10 @@ function Get-ServiceNowRequestItem { [parameter(Mandatory = $false)] [int]$Limit = 10, + # Fields to return + [parameter(mandatory = $false)] + [string[]]$Fields, + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(Mandatory = $false)] [hashtable]$MatchExact = @{}, From 68155c937ae370ed503d0bb39f8c92ce24b2b7ec Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 1 Feb 2019 16:00:25 -0600 Subject: [PATCH 125/348] Formatting edits --- .../Public/Get-ServiceNowChangeRequest.ps1 | 10 +++---- .../Get-ServiceNowConfigurationItem.ps1 | 8 +++--- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 14 +++++----- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 2 +- .../Public/Get-ServiceNowRequestItem.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowTable.ps1 | 2 +- .../Public/Get-ServiceNowTableEntry.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowUser.ps1 | 24 ++++++++--------- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 26 +++++++++---------- 9 files changed, 40 insertions(+), 50 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 5ee966e..9850081 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -16,7 +16,7 @@ function Get-ServiceNowChangeRequest { [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] + [Parameter(Mandatory = $false)] [string[]]$Fields, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) @@ -60,18 +60,16 @@ function Get-ServiceNowChangeRequest { $getServiceNowTableSplat = @{ Table = 'change_request' Query = $Query - Limit = $ + Limit = $Limit Fields = $Fields DisplayValues = $DisplayValues } # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { + if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 3a5b8aa..2ab9daa 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -16,7 +16,7 @@ function Get-ServiceNowConfigurationItem { [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] + [Parameter(Mandatory = $false)] [string[]]$Fields, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) @@ -66,12 +66,10 @@ function Get-ServiceNowConfigurationItem { } # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { + if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index d7d9403..29556f5 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -16,7 +16,7 @@ function Get-ServiceNowIncident{ [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] + [Parameter(Mandatory = $false)] [string[]]$Fields, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) @@ -58,20 +58,18 @@ function Get-ServiceNowIncident{ # Table Splat $getServiceNowTableSplat = @{ - Table = 'incident' - Query = $Query - Limit = $Limit + Table = 'incident' + Query = $Query + Limit = $Limit Fields = $Fields DisplayValues = $DisplayValues } # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { + if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index b458230..21629df 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -16,7 +16,7 @@ function Get-ServiceNowRequest { [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] + [Parameter(Mandatory = $false)] [string[]]$Fields, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index e3b002e..efb815f 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -32,7 +32,7 @@ function Get-ServiceNowRequestItem { [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] + [Parameter(Mandatory = $false)] [string[]]$Fields, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 652fd14..5303bbd 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -30,7 +30,7 @@ function Get-ServiceNowTable { [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] + [Parameter(Mandatory = $false)] [string[]]$Fields, # Whether or not to show human readable display values instead of machine values diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index 4c5b132..04275ef 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -39,7 +39,7 @@ function Get-ServiceNowTableEntry { [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] + [Parameter(Mandatory = $false)] [string[]]$Fields, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 31f5897..718c753 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -49,31 +49,29 @@ function Get-ServiceNowUser{ # Query Splat $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy + OrderBy = $OrderBy OrderDirection = $OrderDirection - MatchExact = $MatchExact - MatchContains = $MatchContains + MatchExact = $MatchExact + MatchContains = $MatchContains } $Query = New-ServiceNowQuery @newServiceNowQuerySplat # Table Splat $getServiceNowTableSplat = @{ - Table = 'sys_user' - Query = $Query - Limit = $Limit - Fields = $Fields + Table = 'sys_user' + Query = $Query + Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues } # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { + if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { - $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) - $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } # Perform query and return each object in the format.ps1xml format diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 2fa2dce..7d221f3 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -16,7 +16,7 @@ function Get-ServiceNowUserGroup{ [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] + [Parameter(Mandatory = $false)] [string[]]$Fields, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) @@ -49,31 +49,29 @@ function Get-ServiceNowUserGroup{ # Query Splat $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy + OrderBy = $OrderBy OrderDirection = $OrderDirection - MatchExact = $MatchExact - MatchContains = $MatchContains + MatchExact = $MatchExact + MatchContains = $MatchContains } $Query = New-ServiceNowQuery @newServiceNowQuerySplat # Table Splat $getServiceNowTableSplat = @{ - Table = 'sys_user_group' - Query = $Query - Limit = $Limit - Fields = $Fields + Table = 'sys_user_group' + Query = $Query + Limit = $Limit + Fields = $Fields DisplayValues = $DisplayValues } # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { + if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { - $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) - $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } # Perform query and return each object in the format.ps1xml format From 74475827ac954bc552cc56d59e85f5be14626235 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 1 Feb 2019 16:03:18 -0600 Subject: [PATCH 126/348] Fields param now case insensitive by forcing ToLower after join --- ServiceNow/Public/Get-ServiceNowTable.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 5303bbd..729cc14 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -78,7 +78,7 @@ function Get-ServiceNowTable { } if ($Fields) { - $Body.sysparm_fields = $Fields -join ',' + $Body.sysparm_fields = ($Fields -join ',').ToLower() } # Perform table query and capture results From 1bf7931dd5c9ca89bbd329f100c0110b6e68c076 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 4 Feb 2019 14:16:33 -0600 Subject: [PATCH 127/348] Tweaks to Properties (Fields) parameter and result output --- .../Public/Get-ServiceNowChangeRequest.ps1 | 17 ++++++++++------- .../Public/Get-ServiceNowConfigurationItem.ps1 | 17 ++++++++++------- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 9 ++++++--- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 9 ++++++--- ServiceNow/Public/Get-ServiceNowRequestItem.ps1 | 9 ++++++--- ServiceNow/Public/Get-ServiceNowTable.ps1 | 7 ++++--- ServiceNow/Public/Get-ServiceNowTableEntry.ps1 | 5 +++-- ServiceNow/Public/Get-ServiceNowUser.ps1 | 11 +++++++---- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 9 ++++++--- 9 files changed, 58 insertions(+), 35 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 9850081..a158bd9 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -17,7 +17,8 @@ function Get-ServiceNowChangeRequest { # Fields to return [Parameter(Mandatory = $false)] - [string[]]$Fields, + [Alias('Fields')] + [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] @@ -58,11 +59,11 @@ function Get-ServiceNowChangeRequest { # Table Splat $getServiceNowTableSplat = @{ - Table = 'change_request' - Query = $Query - Limit = $Limit - Fields = $Fields - DisplayValues = $DisplayValues + Table = 'change_request' + Query = $Query + Limit = $Limit + Fields = $Properties + DisplayValues = $DisplayValues } # Update the Table Splat if the parameters have values @@ -76,6 +77,8 @@ function Get-ServiceNowChangeRequest { # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ChangeRequest")} + If (-not $Properties) { + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ChangeRequest")} + } $Result } diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 2ab9daa..3a16c20 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -17,7 +17,8 @@ function Get-ServiceNowConfigurationItem { # Fields to return [Parameter(Mandatory = $false)] - [string[]]$Fields, + [Alias('Fields')] + [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] @@ -58,11 +59,11 @@ function Get-ServiceNowConfigurationItem { # Table Splat $getServiceNowTableSplat = @{ - Table = 'cmdb_ci' - Query = $Query - Limit = $Limit - Fields = $Fields - DisplayValues = $DisplayValues + Table = 'cmdb_ci' + Query = $Query + Limit = $Limit + Fields = $Properties + DisplayValues = $DisplayValues } # Update the Table Splat if the parameters have values @@ -76,6 +77,8 @@ function Get-ServiceNowConfigurationItem { # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ConfigurationItem")} + If (-not $Properties) { + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ConfigurationItem")} + } $Result } diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 29556f5..c419fa8 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -17,7 +17,8 @@ function Get-ServiceNowIncident{ # Fields to return [Parameter(Mandatory = $false)] - [string[]]$Fields, + [Alias('Fields')] + [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] @@ -61,7 +62,7 @@ function Get-ServiceNowIncident{ Table = 'incident' Query = $Query Limit = $Limit - Fields = $Fields + Fields = $Properties DisplayValues = $DisplayValues } @@ -76,6 +77,8 @@ function Get-ServiceNowIncident{ # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.Incident")} + If (-not $Properties) { + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.Incident")} + } $Result } diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index 21629df..cf2362c 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -17,7 +17,8 @@ function Get-ServiceNowRequest { # Fields to return [Parameter(Mandatory = $false)] - [string[]]$Fields, + [Alias('Fields')] + [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] @@ -61,7 +62,7 @@ function Get-ServiceNowRequest { Table = 'sc_request' Query = $Query Limit = $Limit - Fields = $Fields + Fields = $Properties DisplayValues = $DisplayValues } @@ -76,6 +77,8 @@ function Get-ServiceNowRequest { # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0, "ServiceNow.Request")} + If (-not $Properties) { + $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0, "ServiceNow.Request")} + } $Result } diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index efb815f..658ebf3 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -33,7 +33,8 @@ function Get-ServiceNowRequestItem { # Fields to return [Parameter(Mandatory = $false)] - [string[]]$Fields, + [Alias('Fields')] + [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(Mandatory = $false)] @@ -76,7 +77,7 @@ function Get-ServiceNowRequestItem { Table = 'sc_req_item' Query = $Query Limit = $Limit - Fields = $Fields + Fields = $Properties DisplayValues = $DisplayValues } @@ -91,6 +92,8 @@ function Get-ServiceNowRequestItem { # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0,'ServiceNow.Request')} + If (-not $Properties) { + $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0,'ServiceNow.Request')} + } $Result } diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 729cc14..0ae5e0a 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -31,7 +31,8 @@ function Get-ServiceNowTable { # Fields to return [Parameter(Mandatory = $false)] - [string[]]$Fields, + [Alias('Fields')] + [string[]]$Properties, # Whether or not to show human readable display values instead of machine values [Parameter(Mandatory = $false)] @@ -77,8 +78,8 @@ function Get-ServiceNowTable { $Body.sysparm_query = $Query } - if ($Fields) { - $Body.sysparm_fields = ($Fields -join ',').ToLower() + if ($Properties) { + $Body.sysparm_fields = ($Properties -join ',').ToLower() } # Perform table query and capture results diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index 04275ef..89b75fb 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -40,7 +40,8 @@ function Get-ServiceNowTableEntry { # Fields to return [Parameter(Mandatory = $false)] - [string[]]$Fields, + [Alias('Fields')] + [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter(Mandatory = $false)] @@ -86,7 +87,7 @@ function Get-ServiceNowTableEntry { Table = $Table Query = $Query Limit = $Limit - Fields = $Fields + Fields = $Properties DisplayValues = $DisplayValues ErrorAction = 'Stop' } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 718c753..2fe7b2b 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -16,8 +16,9 @@ function Get-ServiceNowUser{ [int]$Limit = 10, # Fields to return - [parameter(mandatory = $false)] - [string[]]$Fields, + [Parameter(Mandatory = $false)] + [Alias('Fields')] + [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] @@ -61,7 +62,7 @@ function Get-ServiceNowUser{ Table = 'sys_user' Query = $Query Limit = $Limit - Fields = $Fields + Fields = $Properties DisplayValues = $DisplayValues } @@ -76,6 +77,8 @@ function Get-ServiceNowUser{ # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.UserAndUserGroup")} + If (-not $Properties) { + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.UserAndUserGroup")} + } $Result } diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 7d221f3..af7fab7 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -17,7 +17,8 @@ function Get-ServiceNowUserGroup{ # Fields to return [Parameter(Mandatory = $false)] - [string[]]$Fields, + [Alias('Fields')] + [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter(Mandatory = $false)] @@ -61,7 +62,7 @@ function Get-ServiceNowUserGroup{ Table = 'sys_user_group' Query = $Query Limit = $Limit - Fields = $Fields + Fields = $Properties DisplayValues = $DisplayValues } @@ -76,6 +77,8 @@ function Get-ServiceNowUserGroup{ # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.UserAndUserGroup")} + If (-not $Properties) { + $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.UserAndUserGroup")} + } $Result } From dbd2eb019266fc3f3bca8869dee99d887f804461 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 4 Feb 2019 15:20:34 -0600 Subject: [PATCH 128/348] Added parameter support to control Step-Version behavior in psake --- Build/build.ps1 | 18 +++++++++++++++--- Build/psake.ps1 | 15 +++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/Build/build.ps1 b/Build/build.ps1 index 930afe3..2c7aaab 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -6,7 +6,12 @@ Warren F. (RamblingCookieMonster) #> [cmdletbinding()] -param ($Task = 'Default') +param ( + $Task = 'Default', + + [ValidateSet('Build','Minor','Major')] + $StepVersionBy = 'Build' +) # Grab nuget bits, install modules, set build variables, start build. Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null @@ -26,5 +31,12 @@ ForEach ($Module in $Modules) { $Path = (Resolve-Path $PSScriptRoot\..).Path Set-BuildEnvironment -Path $Path -Invoke-psake -buildFile $PSScriptRoot\psake.ps1 -taskList $Task -nologo -exit ([int](-not $psake.build_success)) \ No newline at end of file +$invokepsakeSplat = @{ + buildFile = "$PSScriptRoot\psake.ps1" + taskList = $Task + properties = @{'StepVersionBy' = $StepVersionBy} + nologo = $true +} +Invoke-psake @invokepsakeSplat + +exit ([int](-not $psake.build_success)) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index a451eca..c60b3c6 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -1,11 +1,14 @@ # PSake makes variables declared here available in other scriptblocks Properties { # Find the build folder based on build system - $ProjectRoot = Resolve-Path $ENV:BHProjectPath - if(-not $ProjectRoot) - { - $ProjectRoot = Resolve-Path "$PSScriptRoot\.." - } + $ProjectRoot = Resolve-Path $ENV:BHProjectPath + if(-not $ProjectRoot) + { + $ProjectRoot = Resolve-Path "$PSScriptRoot\.." + } + + # + $StepVersionBy = 'Build' $Timestamp = Get-date -uformat "%Y%m%d-%H%M%S" $PSVersion = $PSVersionTable.PSVersion.Major @@ -91,7 +94,7 @@ Task Build -Depends Test { Set-ModuleFunctions -Name $env:BHPSModuleManifest -FunctionsToExport $functions # Bump the module version - $version = [version] (Step-Version (Get-Metadata -Path $env:BHPSModuleManifest)) + $version = [version] (Step-Version -Version (Get-Metadata -Path $env:BHPSModuleManifest) -By $StepVersionBy) $galleryVersion = Get-NextPSGalleryVersion -Name $env:BHProjectName if($version -lt $galleryVersion) { From 9f7c1146a8496e8fb83a3920836adba3aa3f4c1f Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 4 Feb 2019 15:21:43 -0600 Subject: [PATCH 129/348] Added tests to ensure module is configured properly --- Tests/Unit.GenericModule.Tests.ps1 | 91 ++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 Tests/Unit.GenericModule.Tests.ps1 diff --git a/Tests/Unit.GenericModule.Tests.ps1 b/Tests/Unit.GenericModule.Tests.ps1 new file mode 100644 index 0000000..cf4109a --- /dev/null +++ b/Tests/Unit.GenericModule.Tests.ps1 @@ -0,0 +1,91 @@ +$projectRoot = Resolve-Path "$PSScriptRoot\.." +$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") +$moduleName = Split-Path $moduleRoot -Leaf +$modulePath = (Join-Path $moduleRoot "$moduleName.psd1") + +Write-Host "projectRoot: $projectRoot" -f cyan +Write-Host "moduleRoot: $moduleRoot" -f cyan +Write-Host "moduleName: $moduleName" -f cyan +Write-Host "ModulePath: $ModulePath" -f cyan + +$ModuleManifestContent = Get-Content $modulePath + +Describe "Generic Module Tests" -Tag UnitTest,Build { + # Unload the module so it's loaded fresh for testing + Remove-Module $ModuleName -ErrorAction SilentlyContinue + + # Import Module + $ModuleInformation = Import-Module $modulePath -Force -PassThru + It "Module imported successfully" { + $ModuleInformation.Name | Should -Be $moduleName + } + + # Evaluate AliasesToExport + # Context AliasesToExport { + # $AliasesToExportString = $ModuleManifestContent | Where-Object {$_ -match 'AliasesToExport'} + # $DeclaredAliases = $AliasesToExportString.Split(',') | + # ForEach-Object{If ($_ -match '\w+-\w+'){$Matches[0]}} + + # It "AliasesToExport should not be a wildcard" { + # $AliasesToExportString | Should -Not -Match "\'\*\'" + # } + + # $ExportedAliases = $ModuleInformation.ExportedAliases.Values.Name + # ForEach ($Alias in $DeclaredAliases) { + # It "Alias Should -Be Available $Alias " { + # $ExportedAliases -contains $Alias | Should -Be $True + # } + # } + # } + + # Evaluate FunctionsToExport + Context FunctionsToExport { + $FunctionsToExportString = $ModuleManifestContent | Where-Object {$_ -match 'FunctionsToExport'} + $DeclaredFunctions = $FunctionsToExportString.Split(',') | + ForEach-Object{If ($_ -match '\w+-\w+'){$Matches[0]}} + + It "FunctionsToExport should not be a wildcard" { + $FunctionsToExportString | Should -Not -Match "\'\*\'" + } + + $PublishedFunctions = $ModuleInformation.ExportedFunctions.Values.name + ForEach ($PublicFunction in $DeclaredFunctions) { + It "Function Available: $PublicFunction " { + $PublishedFunctions -contains $PublicFunction | Should -Be $True + } + } + } + + # Other Manifest Properties + Context 'Other Manifest Properties' { + It "RootModule property has value"{ + $ModuleInformation.RootModule | Should -Not -BeNullOrEmpty + } + It "Author property has value"{ + $ModuleInformation.Author | Should -Not -BeNullOrEmpty + } + It "Company Name property has value"{ + $ModuleInformation.CompanyName | Should -Not -BeNullOrEmpty + } + It "Description property has value"{ + $ModuleInformation.Description | Should -Not -BeNullOrEmpty + } + It "Copyright property has value"{ + $ModuleInformation.Copyright | Should -Not -BeNullOrEmpty + } + It "License property has value"{ + $ModuleInformation.LicenseURI | Should -Not -BeNullOrEmpty + } + It "Project Link property has value"{ + $ModuleInformation.ProjectURI | Should -Not -BeNullOrEmpty + } + It "Tags (For the PSGallery) property has value"{ + $ModuleInformation.Tags.count | Should -Not -BeNullOrEmpty + } + It "PSGallery Tags Should Not Contain Spaces" { + ForEach ($Tag in $ModuleInformation.PrivateData.Values.Tags) { + $Tag | Should -Not -Match '\s' + } + } + } +} From 7b91f46dbc3645a97a39c4c4a8374295de9929d5 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 4 Feb 2019 15:22:07 -0600 Subject: [PATCH 130/348] v1.4.0 --- ServiceNow/ServiceNow.psd1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 18ce9cf..7f98796 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.3.6' +ModuleVersion = '1.4.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -113,3 +113,9 @@ PrivateData = @{ + + + + + + From 162d8cc42d9ed31c92752689b7d38fbd9ae24d59 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Mon, 4 Feb 2019 16:57:39 -0600 Subject: [PATCH 131/348] v1.4.1 - Added ServiceNow.RequestItem format --- ServiceNow/ServiceNow.format.ps1xml | 60 +++++++++++++++++++++++++++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index 5f0c18c..cb3401f 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -130,6 +130,66 @@ + + ServiceNow.RequestItem + + ServiceNow.RequestItem + + + + + + 12 + + + + 25 + + + + 8 + + + + 15 + + + + 10 + + + + 21 + + + + + + + number + + + short_description + + + state + + + + $_.assigned_to.display_value + + + + approval + + + opened_at + + + + + + ServiceNow.ConfigurationItem diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 7f98796..b209577 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.4.0' +ModuleVersion = '1.4.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From b7caaa906cbc585f607d7c2eaf31afc1cf18b859 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 5 Feb 2019 08:34:06 -0600 Subject: [PATCH 132/348] ServiceNow attachment functions --- .../Public/Add-ServiceNowAttachment.ps1 | 161 ++++++++++++++++++ .../Public/Get-ServiceNowAttachment.ps1 | 109 ++++++++++++ .../Public/Get-ServiceNowAttachmentDetail.ps1 | 142 +++++++++++++++ .../Public/Remove-ServiceNowAttachment.ps1 | 85 +++++++++ ServiceNow/ServiceNow.psd1 | 2 +- 5 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 ServiceNow/Public/Add-ServiceNowAttachment.ps1 create mode 100644 ServiceNow/Public/Get-ServiceNowAttachment.ps1 create mode 100644 ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 create mode 100644 ServiceNow/Public/Remove-ServiceNowAttachment.ps1 diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 new file mode 100644 index 0000000..87464e6 --- /dev/null +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -0,0 +1,161 @@ +Function Add-ServiceNowAttachment { + <# + .SYNOPSIS + + .DESCRIPTION + + .EXAMPLE + Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt, .\File02.txt + + Upload one or more files to a ServiceNow ticket by specifing the number and table + + .EXAMPLE + Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt -ContentType 'text/plain' + + Upload a file and specify the MIME type (content type). Should only be required if the function cannot automatically determine the type. + + .EXAMPLE + Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt -PassThru + + Upload a file and receive back the file details. + + .OUTPUTS + System.Management.Automation.PSCustomObject + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [OutputType([PSCustomObject[]])] + [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + Param( + # Object number + [Parameter(Mandatory=$true)] + [string]$Number, + + # Table containing the entry + [Parameter(Mandatory=$true)] + [string]$Table, + + # Filter results by file name + [parameter(Mandatory=$true)] + [ValidateScript({ + Test-Path $_ + })] + [string[]]$File, + + # Content (MIME) type - if not automatically determined + [Parameter(Mandatory=$false)] + [string]$ContentType, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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, + + # Allow the results to be shown + [Parameter()] + [switch]$PassThru + ) + + begin {} + process { + Try { + # Use the number and table to determine the sys_id + $getServiceNowTableEntry = @{ + Table = $Table + MatchExact = @{number = $number} + ErrorAction = 'Stop' + } + + # Update the Table Splat if an applicable parameter set name is in use + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $getServiceNowTableEntry.Add('Credential', $Credential) + $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) + } + 'UseConnectionObject' { + $getServiceNowTableEntry.Add('Connection', $Connection) + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $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" + } + } + } + + Write-Verbose "Looking up the ticket number sys_id" + $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } + } + } + + ForEach ($Object in $File) { + $FileData = Get-ChildItem $Object -ErrorAction Stop + If (-not $ContentType) { + Add-Type -AssemblyName 'System.Web' + $ContentType = [System.Web.MimeMapping]::GetMimeMapping($FileData.FullName) + } + + # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot + $URI = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ServiceNowURL,$Table,$TableSysID,$FileData.Name + + $invokeRestMethodSplat = @{ + Uri = $Uri + Headers = @{'Content-Type' = $ContentType} + Method = 'POST' + InFile = $FileData.FullName + Credential = $Credential + } + + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { + $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result + + If ($PassThru) { + $Result | Update-ServiceNowDateTimeField + } + } + } + } + Catch { + Write-Error $PSItem + } + } + end {} +} diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 new file mode 100644 index 0000000..4b84336 --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -0,0 +1,109 @@ +Function Get-ServiceNowAttachment { + <# + .SYNOPSIS + Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + + .DESCRIPTION + Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + + .EXAMPLE + Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' -Destination $Destination + + Save the attachment with the specified sys_id to the destination with a name of 'mynewfile.txt' + + .EXAMPLE + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destination + + Save all attachments from the ticket to the destination. Filenames will be assigned from the attachment name. + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + Param( + # Object number + [Parameter( + Mandatory=$true, + ValueFromPipelineByPropertyName = $true + )] + [Alias('sys_id')] + [string]$SysID, + + [Parameter( + Mandatory=$true, + ValueFromPipelineByPropertyName = $true + )] + [Alias('file_name')] + [string]$FileName, + + # Out path to download files + [parameter(Mandatory=$false)] + [ValidateScript({ + Test-Path $_ + })] + [string]$Destination, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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 + ) + + begin {} + process { + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } + } + } + + # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file + $Uri = $ServiceNowURL + '/' + $SysID + '/file' + + $OutFile = $Null + $OutFile = Join-Path $Destination $FileName + + $invokeRestMethodSplat = @{ + Uri = $Uri + Credential = $Credential + OutFile = $OutFile + } + + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { + Invoke-RestMethod @invokeRestMethodSplat + } + + } + end {} +} diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 new file mode 100644 index 0000000..649f2c9 --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -0,0 +1,142 @@ +Function Get-ServiceNowAttachmentDetail { + <# + .SYNOPSIS + List details for ServiceNow attachments associated with a ticket number. + + .DESCRIPTION + List details for ServiceNow attachments associated with a ticket number. + + .EXAMPLE + Get-ServiceNowAttachmentDetail -Number $Number -Table $Table + + List attachment details + + .EXAMPLE + Get-ServiceNowAttachmentDetail -Number $Number -Table $Table -FileName filename.txt,report.csv + + List details for only filename.txt, and report.csv (if they exist). + + .OUTPUTS + System.Management.Automation.PSCustomObject + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [OutputType([System.Management.Automation.PSCustomObject[]])] + [CmdletBinding(DefaultParameterSetName)] + Param( + # Object number + [Parameter(Mandatory=$true)] + [string]$Number, + + # Table containing the entry + [Parameter(Mandatory=$true)] + [string]$Table, + + # Filter results by file name + [parameter(Mandatory=$false)] + [string[]]$FileName, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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 + ) + + begin {} + process { + Try { + # Use the number and table to determine the sys_id + $getServiceNowTableEntry = @{ + Table = $Table + MatchExact = @{number = $number} + ErrorAction = 'Stop' + } + + # Update the Table Splat if an applicable parameter set name is in use + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $getServiceNowTableEntry.Add('Credential', $Credential) + $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) + } + 'UseConnectionObject' { + $getServiceNowTableEntry.Add('Connection', $Connection) + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $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" + } + } + } + + Write-Verbose "Looking up the ticket number sys_id" + $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } + } + } + + # Populate the query + $Body = @{'sysparm_limit' = 500; 'table_name' = $Table; 'table_sys_id' = $SysID} + $Body.sysparm_query = 'ORDERBYfile_name^ORDERBYDESC' + + # Perform table query and capture results + $Uri = $ServiceNowURL + + $invokeRestMethodSplat = @{ + Uri = $Uri + Body = $Body + Credential = $Credential + ContentType = 'application/json' + } + $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result + + # Filter for requested file names + If ($FileName) { + $Result = $Result | Where-Object {$PSItem.file_name -match ($FileName -join '|')} + } + + $Result + } + Catch { + Write-Error $PSItem + } + } + end {} +} diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 new file mode 100644 index 0000000..65fd64b --- /dev/null +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -0,0 +1,85 @@ +Function Remove-ServiceNowAttachment { + <# + .SYNOPSIS + Remove a ServiceNow attachment by sys_id. + + .DESCRIPTION + Remove a ServiceNow attachment by sys_id. + + .EXAMPLE + Remove-ServiceNowAttachment -SysID $SysID + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + Param( + # Attachment sys_id + [Parameter( + Mandatory=$true, + ValueFromPipelineByPropertyName = $true + )] + [Alias('sys_id')] + [string]$SysID, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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 + ) + + begin {} + process { + # DELETE: https://tenant.service-now.com/api/now/v1/attachment/{sys_id} + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } + } + } + + $Uri = $ServiceNowURL + '/' + $SysID + Write-Verbose "URI: $Uri" + + $invokeRestMethodSplat = @{ + Uri = $Uri + Credential = $Credential + Method = 'Delete' + } + + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { + (Invoke-RestMethod @invokeRestMethodSplat).Result + } + } + end {} +} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index b209577..7d7004e 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Remove-ServiceNowAttachment') # List of all modules packaged with this module # ModuleList = @() From e10cf24768f5c5f8d446633650842fed487f4c95 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Tue, 5 Feb 2019 11:44:32 -0600 Subject: [PATCH 133/348] Add support for PowerShell paging --- .../Public/Get-ServiceNowChangeRequest.ps1 | 15 ++++-- .../Get-ServiceNowConfigurationItem.ps1 | 15 ++++-- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 15 ++++-- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 15 ++++-- .../Public/Get-ServiceNowRequestItem.ps1 | 15 ++++-- ServiceNow/Public/Get-ServiceNowTable.ps1 | 46 +++++++++++++++++-- .../Public/Get-ServiceNowTableEntry.ps1 | 15 ++++-- ServiceNow/Public/Get-ServiceNowUser.ps1 | 13 +++++- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 15 ++++-- 9 files changed, 138 insertions(+), 26 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index a158bd9..f0eb079 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowChangeRequest { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -13,7 +13,7 @@ function Get-ServiceNowChangeRequest { # Maximum number of records to return [Parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -61,7 +61,6 @@ function Get-ServiceNowChangeRequest { $getServiceNowTableSplat = @{ Table = 'change_request' Query = $Query - Limit = $Limit Fields = $Properties DisplayValues = $DisplayValues } @@ -75,6 +74,16 @@ function Get-ServiceNowChangeRequest { $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } + # Only add the Limit parameter if it was explicitly provided + if ($PSBoundParameters.ContainsKey('Limit')) { + $getServiceNowTableSplat.Add('Limit', $Limit) + } + + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) + } + # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 3a16c20..1bb3a50 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowConfigurationItem { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -13,7 +13,7 @@ function Get-ServiceNowConfigurationItem { # Maximum number of records to return [Parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -61,7 +61,6 @@ function Get-ServiceNowConfigurationItem { $getServiceNowTableSplat = @{ Table = 'cmdb_ci' Query = $Query - Limit = $Limit Fields = $Properties DisplayValues = $DisplayValues } @@ -75,6 +74,16 @@ function Get-ServiceNowConfigurationItem { $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } + # Only add the Limit parameter if it was explicitly provided + if ($PSBoundParameters.ContainsKey('Limit')) { + $getServiceNowTableSplat.Add('Limit', $Limit) + } + + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) + } + # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index c419fa8..ea4e0b2 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowIncident{ [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -13,7 +13,7 @@ function Get-ServiceNowIncident{ # Maximum number of records to return [Parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -61,7 +61,6 @@ function Get-ServiceNowIncident{ $getServiceNowTableSplat = @{ Table = 'incident' Query = $Query - Limit = $Limit Fields = $Properties DisplayValues = $DisplayValues } @@ -75,6 +74,16 @@ function Get-ServiceNowIncident{ $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) } + # Only add the Limit parameter if it was explicitly provided + if ($PSBoundParameters.ContainsKey('Limit')) { + $getServiceNowTableSplat.Add('Limit', $Limit) + } + + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) + } + # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index cf2362c..69ebf1a 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowRequest { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -13,7 +13,7 @@ function Get-ServiceNowRequest { # Maximum number of records to return [Parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -61,7 +61,6 @@ function Get-ServiceNowRequest { $getServiceNowTableSplat = @{ Table = 'sc_request' Query = $Query - Limit = $Limit Fields = $Properties DisplayValues = $DisplayValues } @@ -75,6 +74,16 @@ function Get-ServiceNowRequest { $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } + # Only add the Limit parameter if it was explicitly provided + if ($PSBoundParameters.ContainsKey('Limit')) { + $getServiceNowTableSplat.Add('Limit', $Limit) + } + + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) + } + # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index 00703ee..559ddb5 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -16,7 +16,7 @@ function Get-ServiceNowRequestItem { #> [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] param( # Machine name of the field to order by [parameter(Mandatory = $false)] @@ -29,7 +29,7 @@ function Get-ServiceNowRequestItem { # Maximum number of records to return [parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -76,7 +76,6 @@ function Get-ServiceNowRequestItem { $getServiceNowTableSplat = @{ Table = 'sc_req_item' Query = $Query - Limit = $Limit Fields = $Properties DisplayValues = $DisplayValues } @@ -90,6 +89,16 @@ function Get-ServiceNowRequestItem { $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } + # Only add the Limit parameter if it was explicitly provided + if ($PSBoundParameters.ContainsKey('Limit')) { + $getServiceNowTableSplat.Add('Limit', $Limit) + } + + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) + } + # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 0ae5e0a..0ffcb9f 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -14,7 +14,7 @@ function Get-ServiceNowTable { #> [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] Param ( # Name of the table we're querying (e.g. incidents) [parameter(Mandatory = $true)] @@ -27,7 +27,7 @@ function Get-ServiceNowTable { # Maximum number of records to return [Parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -72,8 +72,48 @@ function Get-ServiceNowTable { 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 = @{'sysparm_display_value' = $DisplayValues} + + # Handle paging parameters + # If -Limit was provided, write a warning message, but prioritize it over -First. + # The value of -First defaults to [uint64]::MaxValue if not specified. + # If no paging information was provided, default to the legacy behavior, which was to return 10 records. + + if ($PSBoundParameters.ContainsKey('Limit')) { + Write-Warning "The -Limit parameter is deprecated, and may be removed in a future release. Use the -First parameter instead." + $Body['sysparm_limit'] = $Limit + } + elseif ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) { + $Body['sysparm_limit'] = $PSCmdlet.PagingParameters.First + } + else { + $Body['sysparm_limit'] = 10 + } + + if ($PSCmdlet.PagingParameters.Skip) { + $Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip + } + + if ($PSCmdlet.PagingParameters.IncludeTotalCount) { + # Accuracy is a double between 0.0 and 1.0 representing an estimated percentage accuracy. + # 0.0 means we have no idea and 1.0 means the number is exact. + + # ServiceNow does return this information in the X-Total-Count response header, + # but we're currently using Invoke-RestMethod to perform the API call, and Invoke-RestMethod + # does not provide the response headers, so we can't capture this info. + + # To properly support this parameter, we'd need to fall back on Invoke-WebRequest, read the + # X-Total-Count header of the response, and update this parameter after performing the API + # call. + + # Reference: + # https://developer.servicenow.com/app.do#!/rest_api_doc?v=jakarta&id=r_TableAPI-GET + + [double] $accuracy = 0.0 + $PSCmdlet.PagingParameters.NewTotalCount($PSCmdlet.PagingParameters.First, $accuracy) + } + # Populate the query - $Body = @{'sysparm_limit' = $Limit; 'sysparm_display_value' = $DisplayValues} if ($Query) { $Body.sysparm_query = $Query } diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index 89b75fb..c2cd977 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -19,7 +19,7 @@ function Get-ServiceNowTableEntry { #> - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] param( # Table containing the entry we're deleting [parameter(mandatory = $true)] @@ -36,7 +36,7 @@ function Get-ServiceNowTableEntry { # Maximum number of records to return [parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -86,7 +86,6 @@ function Get-ServiceNowTableEntry { $getServiceNowTableSplat = @{ Table = $Table Query = $Query - Limit = $Limit Fields = $Properties DisplayValues = $DisplayValues ErrorAction = 'Stop' @@ -104,6 +103,16 @@ function Get-ServiceNowTableEntry { Default {} } + # Only add the Limit parameter if it was explicitly provided + if ($PSBoundParameters.ContainsKey('Limit')) { + $getServiceNowTableSplat.Add('Limit', $Limit) + } + + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) + } + # Perform table query and return each object. No fancy formatting here as this can pull tables with unknown default properties Get-ServiceNowTable @getServiceNowTableSplat } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 2fe7b2b..ec9fcf3 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -13,7 +13,7 @@ function Get-ServiceNowUser{ # Maximum number of records to return [Parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -61,7 +61,6 @@ function Get-ServiceNowUser{ $getServiceNowTableSplat = @{ Table = 'sys_user' Query = $Query - Limit = $Limit Fields = $Properties DisplayValues = $DisplayValues } @@ -75,6 +74,16 @@ function Get-ServiceNowUser{ $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } + # Only add the Limit parameter if it was explicitly provided + if ($PSBoundParameters.ContainsKey('Limit')) { + $getServiceNowTableSplat.Add('Limit', $Limit) + } + + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) + } + # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index af7fab7..16d97cb 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowUserGroup{ [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -13,7 +13,7 @@ function Get-ServiceNowUserGroup{ # Maximum number of records to return [Parameter(Mandatory = $false)] - [int]$Limit = 10, + [int]$Limit, # Fields to return [Parameter(Mandatory = $false)] @@ -61,7 +61,6 @@ function Get-ServiceNowUserGroup{ $getServiceNowTableSplat = @{ Table = 'sys_user_group' Query = $Query - Limit = $Limit Fields = $Properties DisplayValues = $DisplayValues } @@ -75,6 +74,16 @@ function Get-ServiceNowUserGroup{ $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } + # Only add the Limit parameter if it was explicitly provided + if ($PSBoundParameters.ContainsKey('Limit')) { + $getServiceNowTableSplat.Add('Limit', $Limit) + } + + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) + } + # Perform query and return each object in the format.ps1xml format $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { From e253e86ad44b38285fdb9f735c66c60f4b094d1a Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 5 Feb 2019 15:10:19 -0600 Subject: [PATCH 134/348] CBH Edits --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 11 +++++++++++ ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 | 11 ++++++++++- ServiceNow/Public/Remove-ServiceNowAttachment.ps1 | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 87464e6..957bd25 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -1,8 +1,19 @@ Function Add-ServiceNowAttachment { <# .SYNOPSIS + Attaches a file to an existing ticket. .DESCRIPTION + Attaches a file to an existing ticket. + + .PARAMETER Number + ServiceNow ticket number + + .PARAMETER Table + ServiceNow ticket table name + + .PARAMETER File + A valid path to the file to attach .EXAMPLE Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt, .\File02.txt diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 649f2c9..6e3ab60 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -6,6 +6,15 @@ Function Get-ServiceNowAttachmentDetail { .DESCRIPTION List details for ServiceNow attachments associated with a ticket number. + .PARAMETER Number + ServiceNow ticket number + + .PARAMETER Table + ServiceNow ticket table name + + .PARAMETER FileName + Filter for one or more file names. Works like a 'match' where partial file names are valid. + .EXAMPLE Get-ServiceNowAttachmentDetail -Number $Number -Table $Table @@ -14,7 +23,7 @@ Function Get-ServiceNowAttachmentDetail { .EXAMPLE Get-ServiceNowAttachmentDetail -Number $Number -Table $Table -FileName filename.txt,report.csv - List details for only filename.txt, and report.csv (if they exist). + List details for only filename.txt and report.csv (if they exist). .OUTPUTS System.Management.Automation.PSCustomObject diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index 65fd64b..cd8603b 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -9,6 +9,13 @@ Function Remove-ServiceNowAttachment { .EXAMPLE Remove-ServiceNowAttachment -SysID $SysID + Removes the attachment with the associated sys_id + + .EXAMPLE + Get-ServiceNowAttachmentDetail -Number CHG0000001 | Remove-ServiceNowAttachment + + Removes all attachments from CHG0000001 + .NOTES #> From 25c8ffdc5fcc9861f616fd025aa5633622b31dcf Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 5 Feb 2019 15:10:49 -0600 Subject: [PATCH 135/348] CBH Edits, Added parameters and associated logic --- .../Public/Get-ServiceNowAttachment.ps1 | 118 ++++++++++++------ 1 file changed, 82 insertions(+), 36 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 4b84336..aabb353 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -6,15 +6,40 @@ Function Get-ServiceNowAttachment { .DESCRIPTION Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + .PARAMETER SysID + The ServiceNow sys_id of the file + + .PARAMETER FileName + File name the file is saved as. Do not include the path. + + .PARAMETER Destination + Path the file is saved to. Do not include the file name. + + .PARAMETER AllowOverwrite + Allows the function to overwrite the existing file. + + .PARAMETER AppendNameWithSysID + Adds the SysID to the file name. Intended for use when a ticket has multiple files with the same name. + + .EXAMPLE + Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' + + Save the attachment with the specified sys_id with a name of 'mynewfile.txt' + + .EXAMPLE + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment + + Save all attachments from the ticket. Filenames will be assigned from the attachment name. + .EXAMPLE - Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' -Destination $Destination + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -AppendNameWithSysID - Save the attachment with the specified sys_id to the destination with a name of 'mynewfile.txt' + Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id. .EXAMPLE - Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destination + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destionion -AllowOverwrite - Save all attachments from the ticket to the destination. Filenames will be assigned from the attachment name. + Save all attachments from the ticketto the destination allowing for overwriting the destination file. .NOTES @@ -45,7 +70,15 @@ Function Get-ServiceNowAttachment { [ValidateScript({ Test-Path $_ })] - [string]$Destination, + [string]$Destination = $PWD.Path, + + # Options impacting downloads + [parameter(Mandatory=$false)] + [switch]$AllowOverwrite, + + # Options impacting downloads + [parameter(Mandatory=$false)] + [switch]$AppendNameWithSysID, # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] @@ -66,42 +99,55 @@ Function Get-ServiceNowAttachment { begin {} process { - - # Process credential steps based on parameter set name - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - } - 'UseConnectionObject' { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - } - Default { - If ((Test-ServiceNowAuthIsSet)) { - $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + Try { + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' } - 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" + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } } } - } - - # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file - $Uri = $ServiceNowURL + '/' + $SysID + '/file' - - $OutFile = $Null - $OutFile = Join-Path $Destination $FileName + + # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file + $Uri = $ServiceNowURL + '/' + $SysID + '/file' + + If ($True -eq $AppendNameWithSysID) { + $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), + $SysID,[io.path]::GetExtension($FileName) + } + $OutFile = $Null + $OutFile = Join-Path $Destination $FileName - $invokeRestMethodSplat = @{ - Uri = $Uri - Credential = $Credential - OutFile = $OutFile + If ((Test-Path $OutFile) -and -not $AllowOverwrite) { + $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile + Throw $ThrowMessage + } + + $invokeRestMethodSplat = @{ + Uri = $Uri + Credential = $Credential + OutFile = $OutFile + } + + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { + Invoke-RestMethod @invokeRestMethodSplat + } } - - If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { - Invoke-RestMethod @invokeRestMethodSplat + Catch { + Write-Error $PSItem } } From 6aab82ca79a30533060754a5b1e9ed311abae914 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 5 Feb 2019 15:49:17 -0600 Subject: [PATCH 136/348] Changed If logic to use ContainsKey --- ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index aabb353..40f3b2f 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -124,14 +124,15 @@ Function Get-ServiceNowAttachment { # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file $Uri = $ServiceNowURL + '/' + $SysID + '/file' - If ($True -eq $AppendNameWithSysID) { + If ($True -eq $PSBoundParameters.ContainsKey('AppendNameWithSysID')) { + Write-Verbose "SYSID in name" $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), $SysID,[io.path]::GetExtension($FileName) } $OutFile = $Null $OutFile = Join-Path $Destination $FileName - If ((Test-Path $OutFile) -and -not $AllowOverwrite) { + If ((Test-Path $OutFile) -and -not $PSBoundParameters.ContainsKey('AllowOverwrite')) { $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile Throw $ThrowMessage } From 56116c92fe958419d11d51f5b838e2f996536bd7 Mon Sep 17 00:00:00 2001 From: Joshua T Date: Thu, 7 Feb 2019 11:06:21 -0600 Subject: [PATCH 137/348] Bugfix - add missing SupportsPaging attribute --- ServiceNow/Public/Get-ServiceNowUser.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index ec9fcf3..5ffb832 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowUser{ [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName)] + [CmdletBinding(DefaultParameterSetName, SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] From 0e55e6bfdb820e69c443ee1cfd16bfb65e55bc42 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 8 Feb 2019 15:38:02 -0600 Subject: [PATCH 138/348] v1.5.0 --- Readme.md | 2 +- ServiceNow/ServiceNow.psd1 | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 00583e3..6545d4a 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-78%25-yellow.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-79%25-yellow.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. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index b209577..5cb6a24 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.4.1' +ModuleVersion = '1.5.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -117,5 +117,7 @@ PrivateData = @{ + + From 95b741f271f4e021f1898c7462e00aae49da6363 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 5 Feb 2019 08:34:06 -0600 Subject: [PATCH 139/348] ServiceNow attachment functions --- .../Public/Add-ServiceNowAttachment.ps1 | 161 ++++++++++++++++++ .../Public/Get-ServiceNowAttachment.ps1 | 109 ++++++++++++ .../Public/Get-ServiceNowAttachmentDetail.ps1 | 142 +++++++++++++++ .../Public/Remove-ServiceNowAttachment.ps1 | 85 +++++++++ ServiceNow/ServiceNow.psd1 | 2 +- 5 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 ServiceNow/Public/Add-ServiceNowAttachment.ps1 create mode 100644 ServiceNow/Public/Get-ServiceNowAttachment.ps1 create mode 100644 ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 create mode 100644 ServiceNow/Public/Remove-ServiceNowAttachment.ps1 diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 new file mode 100644 index 0000000..87464e6 --- /dev/null +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -0,0 +1,161 @@ +Function Add-ServiceNowAttachment { + <# + .SYNOPSIS + + .DESCRIPTION + + .EXAMPLE + Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt, .\File02.txt + + Upload one or more files to a ServiceNow ticket by specifing the number and table + + .EXAMPLE + Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt -ContentType 'text/plain' + + Upload a file and specify the MIME type (content type). Should only be required if the function cannot automatically determine the type. + + .EXAMPLE + Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt -PassThru + + Upload a file and receive back the file details. + + .OUTPUTS + System.Management.Automation.PSCustomObject + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [OutputType([PSCustomObject[]])] + [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + Param( + # Object number + [Parameter(Mandatory=$true)] + [string]$Number, + + # Table containing the entry + [Parameter(Mandatory=$true)] + [string]$Table, + + # Filter results by file name + [parameter(Mandatory=$true)] + [ValidateScript({ + Test-Path $_ + })] + [string[]]$File, + + # Content (MIME) type - if not automatically determined + [Parameter(Mandatory=$false)] + [string]$ContentType, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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, + + # Allow the results to be shown + [Parameter()] + [switch]$PassThru + ) + + begin {} + process { + Try { + # Use the number and table to determine the sys_id + $getServiceNowTableEntry = @{ + Table = $Table + MatchExact = @{number = $number} + ErrorAction = 'Stop' + } + + # Update the Table Splat if an applicable parameter set name is in use + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $getServiceNowTableEntry.Add('Credential', $Credential) + $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) + } + 'UseConnectionObject' { + $getServiceNowTableEntry.Add('Connection', $Connection) + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $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" + } + } + } + + Write-Verbose "Looking up the ticket number sys_id" + $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } + } + } + + ForEach ($Object in $File) { + $FileData = Get-ChildItem $Object -ErrorAction Stop + If (-not $ContentType) { + Add-Type -AssemblyName 'System.Web' + $ContentType = [System.Web.MimeMapping]::GetMimeMapping($FileData.FullName) + } + + # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot + $URI = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ServiceNowURL,$Table,$TableSysID,$FileData.Name + + $invokeRestMethodSplat = @{ + Uri = $Uri + Headers = @{'Content-Type' = $ContentType} + Method = 'POST' + InFile = $FileData.FullName + Credential = $Credential + } + + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { + $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result + + If ($PassThru) { + $Result | Update-ServiceNowDateTimeField + } + } + } + } + Catch { + Write-Error $PSItem + } + } + end {} +} diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 new file mode 100644 index 0000000..4b84336 --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -0,0 +1,109 @@ +Function Get-ServiceNowAttachment { + <# + .SYNOPSIS + Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + + .DESCRIPTION + Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + + .EXAMPLE + Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' -Destination $Destination + + Save the attachment with the specified sys_id to the destination with a name of 'mynewfile.txt' + + .EXAMPLE + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destination + + Save all attachments from the ticket to the destination. Filenames will be assigned from the attachment name. + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + Param( + # Object number + [Parameter( + Mandatory=$true, + ValueFromPipelineByPropertyName = $true + )] + [Alias('sys_id')] + [string]$SysID, + + [Parameter( + Mandatory=$true, + ValueFromPipelineByPropertyName = $true + )] + [Alias('file_name')] + [string]$FileName, + + # Out path to download files + [parameter(Mandatory=$false)] + [ValidateScript({ + Test-Path $_ + })] + [string]$Destination, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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 + ) + + begin {} + process { + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } + } + } + + # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file + $Uri = $ServiceNowURL + '/' + $SysID + '/file' + + $OutFile = $Null + $OutFile = Join-Path $Destination $FileName + + $invokeRestMethodSplat = @{ + Uri = $Uri + Credential = $Credential + OutFile = $OutFile + } + + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { + Invoke-RestMethod @invokeRestMethodSplat + } + + } + end {} +} diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 new file mode 100644 index 0000000..649f2c9 --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -0,0 +1,142 @@ +Function Get-ServiceNowAttachmentDetail { + <# + .SYNOPSIS + List details for ServiceNow attachments associated with a ticket number. + + .DESCRIPTION + List details for ServiceNow attachments associated with a ticket number. + + .EXAMPLE + Get-ServiceNowAttachmentDetail -Number $Number -Table $Table + + List attachment details + + .EXAMPLE + Get-ServiceNowAttachmentDetail -Number $Number -Table $Table -FileName filename.txt,report.csv + + List details for only filename.txt, and report.csv (if they exist). + + .OUTPUTS + System.Management.Automation.PSCustomObject + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [OutputType([System.Management.Automation.PSCustomObject[]])] + [CmdletBinding(DefaultParameterSetName)] + Param( + # Object number + [Parameter(Mandatory=$true)] + [string]$Number, + + # Table containing the entry + [Parameter(Mandatory=$true)] + [string]$Table, + + # Filter results by file name + [parameter(Mandatory=$false)] + [string[]]$FileName, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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 + ) + + begin {} + process { + Try { + # Use the number and table to determine the sys_id + $getServiceNowTableEntry = @{ + Table = $Table + MatchExact = @{number = $number} + ErrorAction = 'Stop' + } + + # Update the Table Splat if an applicable parameter set name is in use + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $getServiceNowTableEntry.Add('Credential', $Credential) + $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) + } + 'UseConnectionObject' { + $getServiceNowTableEntry.Add('Connection', $Connection) + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $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" + } + } + } + + Write-Verbose "Looking up the ticket number sys_id" + $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } + } + } + + # Populate the query + $Body = @{'sysparm_limit' = 500; 'table_name' = $Table; 'table_sys_id' = $SysID} + $Body.sysparm_query = 'ORDERBYfile_name^ORDERBYDESC' + + # Perform table query and capture results + $Uri = $ServiceNowURL + + $invokeRestMethodSplat = @{ + Uri = $Uri + Body = $Body + Credential = $Credential + ContentType = 'application/json' + } + $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result + + # Filter for requested file names + If ($FileName) { + $Result = $Result | Where-Object {$PSItem.file_name -match ($FileName -join '|')} + } + + $Result + } + Catch { + Write-Error $PSItem + } + } + end {} +} diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 new file mode 100644 index 0000000..65fd64b --- /dev/null +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -0,0 +1,85 @@ +Function Remove-ServiceNowAttachment { + <# + .SYNOPSIS + Remove a ServiceNow attachment by sys_id. + + .DESCRIPTION + Remove a ServiceNow attachment by sys_id. + + .EXAMPLE + Remove-ServiceNowAttachment -SysID $SysID + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + Param( + # Attachment sys_id + [Parameter( + Mandatory=$true, + ValueFromPipelineByPropertyName = $true + )] + [Alias('sys_id')] + [string]$SysID, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, + + # 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 + ) + + begin {} + process { + # DELETE: https://tenant.service-now.com/api/now/v1/attachment/{sys_id} + + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + } + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } + } + } + + $Uri = $ServiceNowURL + '/' + $SysID + Write-Verbose "URI: $Uri" + + $invokeRestMethodSplat = @{ + Uri = $Uri + Credential = $Credential + Method = 'Delete' + } + + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { + (Invoke-RestMethod @invokeRestMethodSplat).Result + } + } + end {} +} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 5cb6a24..f49e6a2 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') +FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Remove-ServiceNowAttachment') # List of all modules packaged with this module # ModuleList = @() From 37220a832eb483ddfebd367b5dc4fd96872e6bba Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 5 Feb 2019 15:10:19 -0600 Subject: [PATCH 140/348] CBH Edits --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 11 +++++++++++ ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 | 11 ++++++++++- ServiceNow/Public/Remove-ServiceNowAttachment.ps1 | 7 +++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 87464e6..957bd25 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -1,8 +1,19 @@ Function Add-ServiceNowAttachment { <# .SYNOPSIS + Attaches a file to an existing ticket. .DESCRIPTION + Attaches a file to an existing ticket. + + .PARAMETER Number + ServiceNow ticket number + + .PARAMETER Table + ServiceNow ticket table name + + .PARAMETER File + A valid path to the file to attach .EXAMPLE Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt, .\File02.txt diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 649f2c9..6e3ab60 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -6,6 +6,15 @@ Function Get-ServiceNowAttachmentDetail { .DESCRIPTION List details for ServiceNow attachments associated with a ticket number. + .PARAMETER Number + ServiceNow ticket number + + .PARAMETER Table + ServiceNow ticket table name + + .PARAMETER FileName + Filter for one or more file names. Works like a 'match' where partial file names are valid. + .EXAMPLE Get-ServiceNowAttachmentDetail -Number $Number -Table $Table @@ -14,7 +23,7 @@ Function Get-ServiceNowAttachmentDetail { .EXAMPLE Get-ServiceNowAttachmentDetail -Number $Number -Table $Table -FileName filename.txt,report.csv - List details for only filename.txt, and report.csv (if they exist). + List details for only filename.txt and report.csv (if they exist). .OUTPUTS System.Management.Automation.PSCustomObject diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index 65fd64b..cd8603b 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -9,6 +9,13 @@ Function Remove-ServiceNowAttachment { .EXAMPLE Remove-ServiceNowAttachment -SysID $SysID + Removes the attachment with the associated sys_id + + .EXAMPLE + Get-ServiceNowAttachmentDetail -Number CHG0000001 | Remove-ServiceNowAttachment + + Removes all attachments from CHG0000001 + .NOTES #> From 15a89ef3b191d1bd98667cedb9c26da34e2f068d Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 5 Feb 2019 15:10:49 -0600 Subject: [PATCH 141/348] CBH Edits, Added parameters and associated logic --- .../Public/Get-ServiceNowAttachment.ps1 | 118 ++++++++++++------ 1 file changed, 82 insertions(+), 36 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 4b84336..aabb353 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -6,15 +6,40 @@ Function Get-ServiceNowAttachment { .DESCRIPTION Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + .PARAMETER SysID + The ServiceNow sys_id of the file + + .PARAMETER FileName + File name the file is saved as. Do not include the path. + + .PARAMETER Destination + Path the file is saved to. Do not include the file name. + + .PARAMETER AllowOverwrite + Allows the function to overwrite the existing file. + + .PARAMETER AppendNameWithSysID + Adds the SysID to the file name. Intended for use when a ticket has multiple files with the same name. + + .EXAMPLE + Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' + + Save the attachment with the specified sys_id with a name of 'mynewfile.txt' + + .EXAMPLE + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment + + Save all attachments from the ticket. Filenames will be assigned from the attachment name. + .EXAMPLE - Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' -Destination $Destination + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -AppendNameWithSysID - Save the attachment with the specified sys_id to the destination with a name of 'mynewfile.txt' + Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id. .EXAMPLE - Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destination + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destionion -AllowOverwrite - Save all attachments from the ticket to the destination. Filenames will be assigned from the attachment name. + Save all attachments from the ticketto the destination allowing for overwriting the destination file. .NOTES @@ -45,7 +70,15 @@ Function Get-ServiceNowAttachment { [ValidateScript({ Test-Path $_ })] - [string]$Destination, + [string]$Destination = $PWD.Path, + + # Options impacting downloads + [parameter(Mandatory=$false)] + [switch]$AllowOverwrite, + + # Options impacting downloads + [parameter(Mandatory=$false)] + [switch]$AppendNameWithSysID, # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] @@ -66,42 +99,55 @@ Function Get-ServiceNowAttachment { begin {} process { - - # Process credential steps based on parameter set name - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - } - 'UseConnectionObject' { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - } - Default { - If ((Test-ServiceNowAuthIsSet)) { - $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + Try { + # Process credential steps based on parameter set name + Switch ($PSCmdlet.ParameterSetName) { + 'SpecifyConnectionFields' { + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' } - 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" + 'UseConnectionObject' { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + } + Default { + If ((Test-ServiceNowAuthIsSet)) { + $Credential = $Global:ServiceNowCredentials + $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + } + 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" + } } } - } - - # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file - $Uri = $ServiceNowURL + '/' + $SysID + '/file' - - $OutFile = $Null - $OutFile = Join-Path $Destination $FileName + + # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file + $Uri = $ServiceNowURL + '/' + $SysID + '/file' + + If ($True -eq $AppendNameWithSysID) { + $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), + $SysID,[io.path]::GetExtension($FileName) + } + $OutFile = $Null + $OutFile = Join-Path $Destination $FileName - $invokeRestMethodSplat = @{ - Uri = $Uri - Credential = $Credential - OutFile = $OutFile + If ((Test-Path $OutFile) -and -not $AllowOverwrite) { + $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile + Throw $ThrowMessage + } + + $invokeRestMethodSplat = @{ + Uri = $Uri + Credential = $Credential + OutFile = $OutFile + } + + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { + Invoke-RestMethod @invokeRestMethodSplat + } } - - If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { - Invoke-RestMethod @invokeRestMethodSplat + Catch { + Write-Error $PSItem } } From 8237fa740beb48d42080c7064f0aa67246fefc5a Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 5 Feb 2019 15:49:17 -0600 Subject: [PATCH 142/348] Changed If logic to use ContainsKey --- ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index aabb353..40f3b2f 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -124,14 +124,15 @@ Function Get-ServiceNowAttachment { # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file $Uri = $ServiceNowURL + '/' + $SysID + '/file' - If ($True -eq $AppendNameWithSysID) { + If ($True -eq $PSBoundParameters.ContainsKey('AppendNameWithSysID')) { + Write-Verbose "SYSID in name" $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), $SysID,[io.path]::GetExtension($FileName) } $OutFile = $Null $OutFile = Join-Path $Destination $FileName - If ((Test-Path $OutFile) -and -not $AllowOverwrite) { + If ((Test-Path $OutFile) -and -not $PSBoundParameters.ContainsKey('AllowOverwrite')) { $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile Throw $ThrowMessage } From e1e3f55479725105eab1000810ed1d06c035b5f8 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 12 Feb 2019 10:00:52 -0600 Subject: [PATCH 143/348] Add private function to support attachment functions --- .../Update-ServiceNowDateTimeField.ps1 | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 ServiceNow/Private/Update-ServiceNowDateTimeField.ps1 diff --git a/ServiceNow/Private/Update-ServiceNowDateTimeField.ps1 b/ServiceNow/Private/Update-ServiceNowDateTimeField.ps1 new file mode 100644 index 0000000..71a90f0 --- /dev/null +++ b/ServiceNow/Private/Update-ServiceNowDateTimeField.ps1 @@ -0,0 +1,67 @@ +Function Update-ServiceNowDateTimeField { + <# + .SYNOPSIS + Attempt to update statically set ServiceNow result fields from string to DateTime fields + + .DESCRIPTION + Attempt to update statically set ServiceNow result fields from string to DateTime fields + + .EXAMPLE + Update-ServiceNowDateTimeField -Result $Result + + .OUTPUTS + System.Management.Automation.PSCustomObject + + .NOTES + + #> + + [OutputType([PSCustomObject[]])] + [CmdletBinding(SupportsShouldProcess)] + param ( + # Pipeline variable + [Parameter( + Mandatory = $true, + ValueFromPipeline = $true + )] + [ValidateNotNullOrEmpty()] + [PSCustomObject[]]$Result + ) + + begin {} + process { + # Convert specific fields to DateTime format + $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') + + If ($PSCmdlet.ShouldProcess($SearchBase,$MyInvocation.MyCommand)) { + ForEach ($SNResult in $Result) { + ForEach ($Property in $ConvertToDateField) { + If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { + Try { + # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now + $CultureDateTimeFormat = (Get-Culture).DateTimeFormat + $DateFormat = $CultureDateTimeFormat.ShortDatePattern + $TimeFormat = $CultureDateTimeFormat.LongTimePattern + $DateTimeFormat = "$DateFormat $TimeFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } + Catch { + Try { + # Universal Format + $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } + Catch { + # If the local culture and universal formats both fail keep the property as a string (Do nothing) + $null = 'Code to make PSSA happy when we just want to suppress errors' + } + } + } + } + } + } + + $Result + } + end {} +} From 35293d8ebf1cadce63502ae39cab631b1863c36c Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 12 Feb 2019 10:04:15 -0600 Subject: [PATCH 144/348] Function cleanup --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 957bd25..5abfcf5 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -13,7 +13,7 @@ Function Add-ServiceNowAttachment { ServiceNow ticket table name .PARAMETER File - A valid path to the file to attach + A valid path to the file to attach .EXAMPLE Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt, .\File02.txt diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 40f3b2f..e604b74 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -120,10 +120,10 @@ Function Get-ServiceNowAttachment { } } } - + # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file $Uri = $ServiceNowURL + '/' + $SysID + '/file' - + If ($True -eq $PSBoundParameters.ContainsKey('AppendNameWithSysID')) { Write-Verbose "SYSID in name" $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), @@ -136,13 +136,13 @@ Function Get-ServiceNowAttachment { $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile Throw $ThrowMessage } - + $invokeRestMethodSplat = @{ Uri = $Uri Credential = $Credential OutFile = $OutFile } - + If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { Invoke-RestMethod @invokeRestMethodSplat } From 45c3ad941b548b8c5b987286b08d47ff9ef77e02 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 12 Feb 2019 10:05:20 -0600 Subject: [PATCH 145/348] Added call to private function to update output datetimefields --- ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 6e3ab60..7d5485a 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -13,7 +13,7 @@ Function Get-ServiceNowAttachmentDetail { ServiceNow ticket table name .PARAMETER FileName - Filter for one or more file names. Works like a 'match' where partial file names are valid. + Filter for one or more file names. Works like a 'match' where partial file names are valid. .EXAMPLE Get-ServiceNowAttachmentDetail -Number $Number -Table $Table @@ -141,7 +141,7 @@ Function Get-ServiceNowAttachmentDetail { $Result = $Result | Where-Object {$PSItem.file_name -match ($FileName -join '|')} } - $Result + $Result | Update-ServiceNowDateTimeField } Catch { Write-Error $PSItem From 3a7771d7e7ba4449c23bc0a732edf75334bb76ce Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 13 Feb 2019 09:32:37 -0600 Subject: [PATCH 146/348] Add ValidateScript to ServiceNowURL parameter --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 3 +++ ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 1 + ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 | 1 + ServiceNow/Public/Remove-ServiceNowAttachment.ps1 | 1 + 4 files changed, 6 insertions(+) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 5abfcf5..05b7f56 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -70,6 +70,7 @@ Function Add-ServiceNowAttachment { # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, @@ -94,6 +95,7 @@ Function Add-ServiceNowAttachment { } # Update the Table Splat if an applicable parameter set name is in use + Write-Verbose $PSCmdlet.ParameterSetName Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { $getServiceNowTableEntry.Add('Credential', $Credential) @@ -115,6 +117,7 @@ Function Add-ServiceNowAttachment { Write-Verbose "Looking up the ticket number sys_id" $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + Write-Verbose "Returned $TableSysID" # Process credential steps based on parameter set name Switch ($PSCmdlet.ParameterSetName) { diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index e604b74..c4528dd 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -88,6 +88,7 @@ Function Get-ServiceNowAttachment { # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 7d5485a..2bf57e5 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -58,6 +58,7 @@ Function Get-ServiceNowAttachmentDetail { # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index cd8603b..593cf1e 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -41,6 +41,7 @@ Function Remove-ServiceNowAttachment { # The URL for the ServiceNow instance being used [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [ValidateScript({Test-ServiceNowURL -Url $_})] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, From a82536cce69236f67a7ae08f3fa79b8dcf20d664 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 13 Feb 2019 12:32:40 -0600 Subject: [PATCH 147/348] Issue #73 fix - Specified connection parameters bug --- .../Public/Get-ServiceNowChangeRequest.ps1 | 6 +++--- .../Public/Get-ServiceNowConfigurationItem.ps1 | 6 +++--- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 6 +++--- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowRequestItem.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowTable.ps1 | 17 +++++++++++------ ServiceNow/Public/Get-ServiceNowTableEntry.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowUser.ps1 | 4 ++-- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 4 ++-- 9 files changed, 27 insertions(+), 22 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index f0eb079..1560bc5 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -67,11 +67,11 @@ function Get-ServiceNowChangeRequest { # Update the Table Splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection',$Connection) + $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) - $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) + $getServiceNowTableSplat.Add('Credential', $Credential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } # Only add the Limit parameter if it was explicitly provided diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 1bb3a50..bd5c273 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -67,11 +67,11 @@ function Get-ServiceNowConfigurationItem { # Update the Table Splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection',$Connection) + $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) - $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) + $getServiceNowTableSplat.Add('Credential', $Credential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } # Only add the Limit parameter if it was explicitly provided diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index ea4e0b2..f092b71 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -67,11 +67,11 @@ function Get-ServiceNowIncident{ # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection',$Connection) + $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('ServiceNowCredential',$ServiceNowCredential) - $getServiceNowTableSplat.Add('ServiceNowURL',$ServiceNowURL) + $getServiceNowTableSplat.Add('Credential', $Credential) + $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } # Only add the Limit parameter if it was explicitly provided diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index 69ebf1a..8d1eb1f 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -70,7 +70,7 @@ function Get-ServiceNowRequest { $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index 559ddb5..cad823a 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -85,7 +85,7 @@ function Get-ServiceNowRequestItem { $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 0ffcb9f..9131767 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -57,15 +57,20 @@ function Get-ServiceNowTable { # Get credential and ServiceNow REST URL if ($null -ne $Connection) { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $ServiceNowCredential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' } - elseif ($null -ne $ServiceNowCredential -and $null -ne $ServiceNowURL) { - Test-ServiceNowURL -Url $ServiceNowURL - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' + elseif ($null -ne $Credential -and $null -ne $ServiceNowURL) { + Try { + $null = Test-ServiceNowURL -Url $ServiceNowURL -ErrorAction Stop + $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' + } + Catch { + Throw $PSItem + } } elseif ((Test-ServiceNowAuthIsSet)) { - $ServiceNowCredential = $Global:ServiceNowCredentials + $Credential = $Global:ServiceNowCredentials $ServiceNowURL = $global:ServiceNowRESTURL } else { @@ -124,7 +129,7 @@ function Get-ServiceNowTable { # Perform table query and capture results $Uri = $ServiceNowURL + "/table/$Table" - $Result = (Invoke-RestMethod -Uri $Uri -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").Result + $Result = (Invoke-RestMethod -Uri $Uri -Credential $Credential -Body $Body -ContentType "application/json").Result # Convert specific fields to DateTime format $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index c2cd977..2d915cb 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -94,7 +94,7 @@ function Get-ServiceNowTableEntry { # Update the Table Splat if an applicable parameter set name is in use Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { - $getServiceNowTableSplat.Add('ServiceNowCredential', $Credential) + $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } 'UseConnectionObject' { diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 5ffb832..a13dcf8 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -67,10 +67,10 @@ function Get-ServiceNowUser{ # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection',$Connection) + $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index 16d97cb..bba2eb9 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -67,10 +67,10 @@ function Get-ServiceNowUserGroup{ # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection',$Connection) + $getServiceNowTableSplat.Add('Connection', $Connection) } elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('ServiceNowCredential', $ServiceNowCredential) + $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } From f0927c4635a2ee695dd5a9a25aac855bcee848ac Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 13 Feb 2019 14:20:58 -0600 Subject: [PATCH 148/348] Add -Force to Set-BuildEnvironment --- Build/build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/build.ps1 b/Build/build.ps1 index 2c7aaab..66edcbb 100644 --- a/Build/build.ps1 +++ b/Build/build.ps1 @@ -29,7 +29,7 @@ ForEach ($Module in $Modules) { } $Path = (Resolve-Path $PSScriptRoot\..).Path -Set-BuildEnvironment -Path $Path +Set-BuildEnvironment -Path $Path -Force $invokepsakeSplat = @{ buildFile = "$PSScriptRoot\psake.ps1" From 4cbad9aff1104bcea07d73b517a14cc1936cec96 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 13 Feb 2019 14:21:18 -0600 Subject: [PATCH 149/348] Updated tests to reflect changes --- Tests/ServiceNow.Tests.ps1 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index 42b04fe..4258295 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -39,6 +39,11 @@ Describe "ServiceNow-Module" { Remove-ServiceNowAuth } + # Validate Environment + It "ServiceNow url has Test-Connection connectivity" { + Test-Connection $Defaults.ServiceNowURL -Quiet | Should -Be $true + } + # Auth Functions It "Test-ServiceNowAuthIsSet not set" { Test-ServiceNowAuthIsSet | Should -Be $false @@ -61,7 +66,7 @@ Describe "ServiceNow-Module" { $getServiceNowTableSplat = @{ Table = 'incident' Query = 'ORDERBYDESCopened_at' - ServiceNowCredential = $Defaults.Creds + Credential = $Defaults.Creds ServiceNowURL = $Defaults.ServiceNowURL } ([array](Get-ServiceNowTable @getServiceNowTableSplat)).Count -gt 0 | Should -Match $true @@ -119,7 +124,7 @@ Describe "ServiceNow-Module" { # Update functions It "Update-ServiceNowChangeRequest works" { - $TestTicket = Get-ServiceNowChangeRequest -Limit 1 + $TestTicket = Get-ServiceNowChangeRequest -First 1 $Values = @{ description = 'Pester Comment: Update-ServiceNowChangeRequest works' @@ -243,7 +248,7 @@ Describe "ServiceNow-Module" { # Remove Functions It "Remove-ServiceNowTable works" { - $TestTicket = Get-ServiceNowIncident -Limit 1 + $TestTicket = Get-ServiceNowIncident -First 1 $removeServiceNowTableEntrySplat = @{ SysId = $TestTicket.sys_id Table = 'incident' From b84104771dd23468ddc287c5f1512bb8c00fc167 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 13 Feb 2019 14:27:11 -0600 Subject: [PATCH 150/348] Incremented ModuleVersion to 1.5.1 --- ServiceNow/ServiceNow.psd1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 5cb6a24..16a8810 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.5.0' +ModuleVersion = '1.5.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -118,6 +118,8 @@ PrivateData = @{ + + From 0fe18915e51f1354d95b1fd11aa5abb652041600 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 14 Feb 2019 11:08:22 -0600 Subject: [PATCH 151/348] One more correction for #73 --- .../Public/Get-ServiceNowChangeRequest.ps1 | 2 +- .../Get-ServiceNowConfigurationItem.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 2 +- .../Public/Get-ServiceNowRequestItem.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowUser.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 2 +- ServiceNow/Public/New-ServiceNowIncident.ps1 | 44 +++++++++---------- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 1560bc5..eb843c0 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -69,7 +69,7 @@ function Get-ServiceNowChangeRequest { if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index bd5c273..e23ac98 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -69,7 +69,7 @@ function Get-ServiceNowConfigurationItem { if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index f092b71..4aacc83 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -69,7 +69,7 @@ function Get-ServiceNowIncident{ if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index 8d1eb1f..5357071 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -69,7 +69,7 @@ function Get-ServiceNowRequest { if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index cad823a..1972c13 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -84,7 +84,7 @@ function Get-ServiceNowRequestItem { if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index a13dcf8..ab969ec 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -69,7 +69,7 @@ function Get-ServiceNowUser{ if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index bba2eb9..d4bae87 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -69,7 +69,7 @@ function Get-ServiceNowUserGroup{ if ($null -ne $PSBoundParameters.Connection) { $getServiceNowTableSplat.Add('Connection', $Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) } diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 449f18c..8b97b30 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -16,21 +16,21 @@ function New-ServiceNowIncident{ .EXAMPLE Generate an Incident by "Splatting" all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow Instance): - $IncidentParams = @{Caller = "UserName" - ShortDescription = "New PS Incident" - Description = "This incident was created from Powershell" - AssignmentGroup "ServiceDesk" - Comment "Inline Comment" - Category "Office" - Subcategory "Outlook" + $IncidentParams = @{Caller = "UserName" + ShortDescription = "New PS Incident" + Description = "This incident was created from Powershell" + AssignmentGroup "ServiceDesk" + Comment "Inline Comment" + Category "Office" + Subcategory "Outlook" ConfigurationItem UserPC1 CustomFields = @{u_custom1 = "Custom Field Entry" u_another_custom = "Related Test"} - } + } New-ServiceNowIncident @Params #> - + Param( # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) @@ -39,7 +39,7 @@ function New-ServiceNowIncident{ [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$Caller, - + # Short description of the incident [parameter(Mandatory=$true)] [parameter(ParameterSetName='SpecifyConnectionFields')] @@ -62,14 +62,14 @@ function New-ServiceNowIncident{ [string]$AssignmentGroup, # Comment to include in the ticket - [parameter(mandatory=$false)] + [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [string]$Comment, # Category of the incident (e.g. 'Network') - [parameter(mandatory=$false)] + [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] @@ -89,25 +89,25 @@ function New-ServiceNowIncident{ [parameter(ParameterSetName='SetGlobalAuth')] [string]$ConfigurationItem, - # custom fields as hashtable + # custom fields as hashtable [parameter(mandatory=$false)] [parameter(ParameterSetName='SpecifyConnectionFields')] [parameter(ParameterSetName='UseConnectionObject')] [parameter(ParameterSetName='SetGlobalAuth')] [hashtable]$CustomFields, - # Credential used to authenticate to ServiceNow + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [PSCredential]$ServiceNowCredential, + [PSCredential]$ServiceNowCredential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, + [string]$ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] [Hashtable]$Connection ) @@ -131,7 +131,7 @@ function New-ServiceNowIncident{ $TableEntryValues.Add($KeyToAdd,$PSBoundParameters.$Parameter) } } - + # Add CustomFields hash pairs to the Table Entry Values hash table If ($null -ne $PSBoundParameters.CustomFields) { $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { @@ -151,7 +151,7 @@ function New-ServiceNowIncident{ $DuplicateKeyList = $DuplicateTableEntryValues -join "," Throw "Ticket fields may only be used once: $DuplicateKeyList" } - + # Table Entry Splat $newServiceNowTableEntrySplat = @{ Table = 'incident' @@ -160,15 +160,15 @@ function New-ServiceNowIncident{ # Update the splat if the parameters have values if ($null -ne $PSBoundParameters.Connection) - { + { $newServiceNowTableEntrySplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $newServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) $newServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) } - + # Create the table entry New-ServiceNowTableEntry @newServiceNowTableEntrySplat } From 33f4406be8f44034aabc166556ebf52a85b4ea6b Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 14 Feb 2019 11:13:40 -0600 Subject: [PATCH 152/348] Increment ModuleVersion --- ServiceNow/ServiceNow.psd1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 16a8810..e546dea 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.5.1' +ModuleVersion = '1.5.2' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -120,6 +120,8 @@ PrivateData = @{ + + From b2354be847c91f5a7fb9baa3e28a6c25333e8bef Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 14 Feb 2019 11:42:52 -0600 Subject: [PATCH 153/348] Sigh...#73 correction. I hid publishes, heh. --- ServiceNow/Public/New-ServiceNowIncident.ps1 | 2 +- ServiceNow/ServiceNow.psd1 | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 8b97b30..f3649c5 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -163,7 +163,7 @@ function New-ServiceNowIncident{ { $newServiceNowTableEntrySplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { $newServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) $newServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index e546dea..11beb3a 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.5.2' +ModuleVersion = '1.5.3' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -122,6 +122,8 @@ PrivateData = @{ + + From 67b2b31b4a9a6ff0733d5de7df07dc54580c4e49 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 14 Feb 2019 15:29:08 -0600 Subject: [PATCH 154/348] Renamed internal variable to $ApiUrl & removed verbose lines --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 11 ++++------- ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 9 ++++----- .../Public/Get-ServiceNowAttachmentDetail.ps1 | 13 ++++++------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 05b7f56..f1d267f 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -95,7 +95,6 @@ Function Add-ServiceNowAttachment { } # Update the Table Splat if an applicable parameter set name is in use - Write-Verbose $PSCmdlet.ParameterSetName Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { $getServiceNowTableEntry.Add('Credential', $Credential) @@ -115,24 +114,22 @@ Function Add-ServiceNowAttachment { } } - Write-Verbose "Looking up the ticket number sys_id" $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id - Write-Verbose "Returned $TableSysID" # Process credential steps based on parameter set name Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' } Default { If ((Test-ServiceNowAuthIsSet)) { $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' } 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" @@ -148,7 +145,7 @@ Function Add-ServiceNowAttachment { } # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot - $URI = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ServiceNowURL,$Table,$TableSysID,$FileData.Name + $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl,$Table,$TableSysID,$FileData.Name $invokeRestMethodSplat = @{ Uri = $Uri diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index c4528dd..7d4f983 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -104,17 +104,17 @@ Function Get-ServiceNowAttachment { # Process credential steps based on parameter set name Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' } Default { If ((Test-ServiceNowAuthIsSet)) { $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' } 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" @@ -123,10 +123,9 @@ Function Get-ServiceNowAttachment { } # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file - $Uri = $ServiceNowURL + '/' + $SysID + '/file' + $Uri = $ApiUrl + '/' + $SysID + '/file' If ($True -eq $PSBoundParameters.ContainsKey('AppendNameWithSysID')) { - Write-Verbose "SYSID in name" $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), $SysID,[io.path]::GetExtension($FileName) } diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 2bf57e5..ae71089 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -98,23 +98,22 @@ Function Get-ServiceNowAttachmentDetail { } } - Write-Verbose "Looking up the ticket number sys_id" - $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id # Process credential steps based on parameter set name Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' } Default { If ((Test-ServiceNowAuthIsSet)) { $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' } 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" @@ -123,11 +122,11 @@ Function Get-ServiceNowAttachmentDetail { } # Populate the query - $Body = @{'sysparm_limit' = 500; 'table_name' = $Table; 'table_sys_id' = $SysID} + $Body = @{'sysparm_limit' = 500; 'table_name' = $Table; 'table_sys_id' = $TableSysID} $Body.sysparm_query = 'ORDERBYfile_name^ORDERBYDESC' # Perform table query and capture results - $Uri = $ServiceNowURL + $Uri = $ApiUrl $invokeRestMethodSplat = @{ Uri = $Uri From 6147e3246ee5bd3d90f0da8398d887f12e2f4de3 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 14 Feb 2019 15:29:28 -0600 Subject: [PATCH 155/348] Adding Pester test drafts --- Tests/AddServiceNowAttachment.Tests.ps1 | 113 +++++++++++++++ Tests/GetServiceNowAttachment.Tests.ps1 | 136 ++++++++++++++++++ Tests/GetServiceNowAttachmentDetail.Tests.ps1 | 126 ++++++++++++++++ 3 files changed, 375 insertions(+) create mode 100644 Tests/AddServiceNowAttachment.Tests.ps1 create mode 100644 Tests/GetServiceNowAttachment.Tests.ps1 create mode 100644 Tests/GetServiceNowAttachmentDetail.Tests.ps1 diff --git a/Tests/AddServiceNowAttachment.Tests.ps1 b/Tests/AddServiceNowAttachment.Tests.ps1 new file mode 100644 index 0000000..c8f8b03 --- /dev/null +++ b/Tests/AddServiceNowAttachment.Tests.ps1 @@ -0,0 +1,113 @@ +[CmdletBinding()] +Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullorEmpty()] + [PSCredential]$Credential +) + +If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} +$Script:ThisCommand = $MyInvocation.MyCommand + +$ProjectRoot = Resolve-Path "$PSScriptRoot\.." +$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") +$ModuleName = Split-Path $ModuleRoot -Leaf +$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path +$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path +$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +$ModuleLoaded = Get-Module $ModuleName +If ($null -eq $ModuleLoaded) { + Import-Module $ModulePSD -Force +} +ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { + Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue + Import-Module $ModulePSD -Force +} + +# Load defaults from file +If (Test-Path $DefaultsFile) { + $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json + + If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { + Throw 'Please populate the *.Pester.Defaults.json file with your values' + } +} +Else { + # Write example file + @{ + ServiceNowURL = 'testingurl.service-now.com' + TestCategory = 'Internal' + TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' + TestUser = '6816f79cc0a8016401c5a33be04be441' + } | ConvertTo-Json | Set-Content $DefaultsFile + Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" +} + +Describe "$ThisCommand" -Tag Attachment { + # It "Test It" {} + + It "Create incident with New-ServiceNowIncident" { + $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + Comment = 'Test Comment' + ServiceNowCredential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should -Be $ShortDescription + } + + It 'Attachment test file exist' { + $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) + $FileName = "{0}.txt" -f 'GetServiceNowAttachment' + $newItemSplat = @{ + Name = $FileName + ItemType = 'File' + Value = $FileValue + } + $Script:File = New-Item @newItemSplat + + $File.FullName | Should -Exist + } + + It "File is attached to $($TestTicket.Number)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + PassThru = $true + } + $Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It 'Attachment test file removed' { + Remove-Item $File.FullName -Force + + $File.FullName | Should -Not -Exist + } +} + +<# + +$Hash = @{ + Path = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell\Tests\GetServiceNowAttachment.Tests.ps1' + Parameters = @{ + Credential = $Credential + } +} + +$invokePesterSplat = @{ + Script = $Hash + Tag = 'Attachment' +} +Invoke-Pester @invokePesterSplat + +#> diff --git a/Tests/GetServiceNowAttachment.Tests.ps1 b/Tests/GetServiceNowAttachment.Tests.ps1 new file mode 100644 index 0000000..0ab37a0 --- /dev/null +++ b/Tests/GetServiceNowAttachment.Tests.ps1 @@ -0,0 +1,136 @@ +[CmdletBinding()] +Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullorEmpty()] + [PSCredential]$Credential +) + +If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} +$Script:ThisCommand = $MyInvocation.MyCommand + +$ProjectRoot = Resolve-Path "$PSScriptRoot\.." +$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") +$ModuleName = Split-Path $ModuleRoot -Leaf +$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path +$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path +$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +$ModuleLoaded = Get-Module $ModuleName +If ($null -eq $ModuleLoaded) { + Import-Module $ModulePSD -Force +} +ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { + Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue + Import-Module $ModulePSD -Force +} + +# Load defaults from file +If (Test-Path $DefaultsFile) { + $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json + + If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { + Throw 'Please populate the *.Pester.Defaults.json file with your values' + } +} +Else { + # Write example file + @{ + ServiceNowURL = 'testingurl.service-now.com' + TestCategory = 'Internal' + TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' + TestUser = '6816f79cc0a8016401c5a33be04be441' + } | ConvertTo-Json | Set-Content $DefaultsFile + Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" +} + +Describe "$ThisCommand" -Tag Attachment { + # It "Test It" {} + + It "Create incident with New-ServiceNowIncident" { + $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + Comment = 'Test Comment' + ServiceNowCredential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should -Be $ShortDescription + } + + It 'Attachment test file exist' { + $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) + $FileName = "{0}.txt" -f 'GetServiceNowAttachment' + $newItemSplat = @{ + Name = $FileName + ItemType = 'File' + Value = $FileValue + } + $Script:File = New-Item @newItemSplat + + $File.FullName | Should -Exist + } + + It "File is attached to $($TestTicket.Number)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + PassThru = $true + } + $Script:Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It 'Attachment test file removed' { + Remove-Item $File.FullName -Force + + $File.FullName | Should -Not -Exist + } + + It 'Attachment downloaded successfully' { + $FileName = 'DownloadServiceNowAttachment.txt' + $Script:ExpectedOutput = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), + $Attachment.sys_id,[io.path]::GetExtension($FileName) + + $getServiceNowAttachmentSplat = @{ + FileName = $FileName + SysId = $Attachment.sys_id + AppendNameWithSysID = $true + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + Get-ServiceNowAttachment @getServiceNowAttachmentSplat + + $ExpectedOutput | Should -Exist + } + + It 'Attachment test file removed' { + Remove-Item $ExpectedOutput -Force + + $ExpectedOutput | Should -Not -Exist + } +} + +<# + +$Hash = @{ + Path = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell\Tests\GetServiceNowAttachment.Tests.ps1' + Parameters = @{ + Credential = $Credential + } +} + +$invokePesterSplat = @{ + Script = $Hash + Tag = 'Attachment' +} +Invoke-Pester @invokePesterSplat + +#> diff --git a/Tests/GetServiceNowAttachmentDetail.Tests.ps1 b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 new file mode 100644 index 0000000..3f093fb --- /dev/null +++ b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 @@ -0,0 +1,126 @@ +[CmdletBinding()] +Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullorEmpty()] + [PSCredential]$Credential +) + +If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} +$Script:ThisCommand = $MyInvocation.MyCommand + +$ProjectRoot = Resolve-Path "$PSScriptRoot\.." +$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") +$ModuleName = Split-Path $ModuleRoot -Leaf +$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path +$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path +$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +$ModuleLoaded = Get-Module $ModuleName +If ($null -eq $ModuleLoaded) { + Import-Module $ModulePSD -Force +} +ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { + Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue + Import-Module $ModulePSD -Force +} + +# Load defaults from file +If (Test-Path $DefaultsFile) { + $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json + + If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { + Throw 'Please populate the *.Pester.Defaults.json file with your values' + } +} +Else { + # Write example file + @{ + ServiceNowURL = 'testingurl.service-now.com' + TestCategory = 'Internal' + TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' + TestUser = '6816f79cc0a8016401c5a33be04be441' + } | ConvertTo-Json | Set-Content $DefaultsFile + Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" +} + +Describe "$ThisCommand" -Tag Attachment { + # It "Test It" {} + + It "Create incident with New-ServiceNowIncident" { + $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + Comment = 'Test Comment' + ServiceNowCredential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should -Be $ShortDescription + } + + It 'Attachment test file exist' { + $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) + $FileName = "{0}.txt" -f 'GetServiceNowAttachment' + $newItemSplat = @{ + Name = $FileName + ItemType = 'File' + Value = $FileValue + } + $Script:File = New-Item @newItemSplat + + $File.FullName | Should -Exist + } + + It "File is attached to $($TestTicket.Number)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + PassThru = $true + } + $Script:Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It 'Attachment test file removed' { + Remove-Item $File.FullName -Force + + $File.FullName | Should -Not -Exist + } + + It 'Attachment detail works' { + $getServiceNowAttachmentDetailSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + FileName = $Attachment.file_name + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + $AttachmentDetail = Get-ServiceNowAttachmentDetail @getServiceNowAttachmentDetailSplat + + $AttachmentDetail.sys_id | Should -Be $Attachment.sys_id + } +} + +<# + +$Hash = @{ + Path = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell\Tests\GetServiceNowAttachmentDetail.Tests.ps1' + Parameters = @{ + Credential = $Credential + } +} + +$invokePesterSplat = @{ + Script = $Hash + Tag = 'Attachment' +} +Invoke-Pester @invokePesterSplat + +#> From bf19b02b8453582e33c564ce4f477a6af2acca73 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 14 Feb 2019 15:52:51 -0600 Subject: [PATCH 156/348] Revert --- Tests/AddServiceNowAttachment.Tests.ps1 | 113 --------------- Tests/GetServiceNowAttachment.Tests.ps1 | 136 ------------------ Tests/GetServiceNowAttachmentDetail.Tests.ps1 | 126 ---------------- 3 files changed, 375 deletions(-) delete mode 100644 Tests/AddServiceNowAttachment.Tests.ps1 delete mode 100644 Tests/GetServiceNowAttachment.Tests.ps1 delete mode 100644 Tests/GetServiceNowAttachmentDetail.Tests.ps1 diff --git a/Tests/AddServiceNowAttachment.Tests.ps1 b/Tests/AddServiceNowAttachment.Tests.ps1 deleted file mode 100644 index c8f8b03..0000000 --- a/Tests/AddServiceNowAttachment.Tests.ps1 +++ /dev/null @@ -1,113 +0,0 @@ -[CmdletBinding()] -Param( - [Parameter(Mandatory = $true)] - [ValidateNotNullorEmpty()] - [PSCredential]$Credential -) - -If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} -$Script:ThisCommand = $MyInvocation.MyCommand - -$ProjectRoot = Resolve-Path "$PSScriptRoot\.." -$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") -$ModuleName = Split-Path $ModuleRoot -Leaf -$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path -$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path -$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" - -$ModuleLoaded = Get-Module $ModuleName -If ($null -eq $ModuleLoaded) { - Import-Module $ModulePSD -Force -} -ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { - Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue - Import-Module $ModulePSD -Force -} - -# Load defaults from file -If (Test-Path $DefaultsFile) { - $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json - - If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { - Throw 'Please populate the *.Pester.Defaults.json file with your values' - } -} -Else { - # Write example file - @{ - ServiceNowURL = 'testingurl.service-now.com' - TestCategory = 'Internal' - TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' - TestUser = '6816f79cc0a8016401c5a33be04be441' - } | ConvertTo-Json | Set-Content $DefaultsFile - Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" -} - -Describe "$ThisCommand" -Tag Attachment { - # It "Test It" {} - - It "Create incident with New-ServiceNowIncident" { - $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" - $newServiceNowIncidentSplat = @{ - Caller = $Defaults.TestUser - ShortDescription = $ShortDescription - Description = 'Long description' - Comment = 'Test Comment' - ServiceNowCredential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL - } - $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat - - $TestTicket.short_description | Should -Be $ShortDescription - } - - It 'Attachment test file exist' { - $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) - $FileName = "{0}.txt" -f 'GetServiceNowAttachment' - $newItemSplat = @{ - Name = $FileName - ItemType = 'File' - Value = $FileValue - } - $Script:File = New-Item @newItemSplat - - $File.FullName | Should -Exist - } - - It "File is attached to $($TestTicket.Number)" { - $addServiceNowAttachmentSplat = @{ - Number = $TestTicket.Number - Table = 'incident' - File = $File.FullName - Credential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL - PassThru = $true - } - $Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat - - $Attachment.file_name | Should -Be $File.Name - } - - It 'Attachment test file removed' { - Remove-Item $File.FullName -Force - - $File.FullName | Should -Not -Exist - } -} - -<# - -$Hash = @{ - Path = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell\Tests\GetServiceNowAttachment.Tests.ps1' - Parameters = @{ - Credential = $Credential - } -} - -$invokePesterSplat = @{ - Script = $Hash - Tag = 'Attachment' -} -Invoke-Pester @invokePesterSplat - -#> diff --git a/Tests/GetServiceNowAttachment.Tests.ps1 b/Tests/GetServiceNowAttachment.Tests.ps1 deleted file mode 100644 index 0ab37a0..0000000 --- a/Tests/GetServiceNowAttachment.Tests.ps1 +++ /dev/null @@ -1,136 +0,0 @@ -[CmdletBinding()] -Param( - [Parameter(Mandatory = $true)] - [ValidateNotNullorEmpty()] - [PSCredential]$Credential -) - -If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} -$Script:ThisCommand = $MyInvocation.MyCommand - -$ProjectRoot = Resolve-Path "$PSScriptRoot\.." -$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") -$ModuleName = Split-Path $ModuleRoot -Leaf -$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path -$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path -$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" - -$ModuleLoaded = Get-Module $ModuleName -If ($null -eq $ModuleLoaded) { - Import-Module $ModulePSD -Force -} -ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { - Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue - Import-Module $ModulePSD -Force -} - -# Load defaults from file -If (Test-Path $DefaultsFile) { - $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json - - If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { - Throw 'Please populate the *.Pester.Defaults.json file with your values' - } -} -Else { - # Write example file - @{ - ServiceNowURL = 'testingurl.service-now.com' - TestCategory = 'Internal' - TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' - TestUser = '6816f79cc0a8016401c5a33be04be441' - } | ConvertTo-Json | Set-Content $DefaultsFile - Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" -} - -Describe "$ThisCommand" -Tag Attachment { - # It "Test It" {} - - It "Create incident with New-ServiceNowIncident" { - $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" - $newServiceNowIncidentSplat = @{ - Caller = $Defaults.TestUser - ShortDescription = $ShortDescription - Description = 'Long description' - Comment = 'Test Comment' - ServiceNowCredential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL - } - $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat - - $TestTicket.short_description | Should -Be $ShortDescription - } - - It 'Attachment test file exist' { - $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) - $FileName = "{0}.txt" -f 'GetServiceNowAttachment' - $newItemSplat = @{ - Name = $FileName - ItemType = 'File' - Value = $FileValue - } - $Script:File = New-Item @newItemSplat - - $File.FullName | Should -Exist - } - - It "File is attached to $($TestTicket.Number)" { - $addServiceNowAttachmentSplat = @{ - Number = $TestTicket.Number - Table = 'incident' - File = $File.FullName - Credential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL - PassThru = $true - } - $Script:Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat - - $Attachment.file_name | Should -Be $File.Name - } - - It 'Attachment test file removed' { - Remove-Item $File.FullName -Force - - $File.FullName | Should -Not -Exist - } - - It 'Attachment downloaded successfully' { - $FileName = 'DownloadServiceNowAttachment.txt' - $Script:ExpectedOutput = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), - $Attachment.sys_id,[io.path]::GetExtension($FileName) - - $getServiceNowAttachmentSplat = @{ - FileName = $FileName - SysId = $Attachment.sys_id - AppendNameWithSysID = $true - Credential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL - } - Get-ServiceNowAttachment @getServiceNowAttachmentSplat - - $ExpectedOutput | Should -Exist - } - - It 'Attachment test file removed' { - Remove-Item $ExpectedOutput -Force - - $ExpectedOutput | Should -Not -Exist - } -} - -<# - -$Hash = @{ - Path = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell\Tests\GetServiceNowAttachment.Tests.ps1' - Parameters = @{ - Credential = $Credential - } -} - -$invokePesterSplat = @{ - Script = $Hash - Tag = 'Attachment' -} -Invoke-Pester @invokePesterSplat - -#> diff --git a/Tests/GetServiceNowAttachmentDetail.Tests.ps1 b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 deleted file mode 100644 index 3f093fb..0000000 --- a/Tests/GetServiceNowAttachmentDetail.Tests.ps1 +++ /dev/null @@ -1,126 +0,0 @@ -[CmdletBinding()] -Param( - [Parameter(Mandatory = $true)] - [ValidateNotNullorEmpty()] - [PSCredential]$Credential -) - -If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} -$Script:ThisCommand = $MyInvocation.MyCommand - -$ProjectRoot = Resolve-Path "$PSScriptRoot\.." -$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") -$ModuleName = Split-Path $ModuleRoot -Leaf -$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path -$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path -$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" - -$ModuleLoaded = Get-Module $ModuleName -If ($null -eq $ModuleLoaded) { - Import-Module $ModulePSD -Force -} -ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { - Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue - Import-Module $ModulePSD -Force -} - -# Load defaults from file -If (Test-Path $DefaultsFile) { - $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json - - If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { - Throw 'Please populate the *.Pester.Defaults.json file with your values' - } -} -Else { - # Write example file - @{ - ServiceNowURL = 'testingurl.service-now.com' - TestCategory = 'Internal' - TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' - TestUser = '6816f79cc0a8016401c5a33be04be441' - } | ConvertTo-Json | Set-Content $DefaultsFile - Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" -} - -Describe "$ThisCommand" -Tag Attachment { - # It "Test It" {} - - It "Create incident with New-ServiceNowIncident" { - $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" - $newServiceNowIncidentSplat = @{ - Caller = $Defaults.TestUser - ShortDescription = $ShortDescription - Description = 'Long description' - Comment = 'Test Comment' - ServiceNowCredential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL - } - $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat - - $TestTicket.short_description | Should -Be $ShortDescription - } - - It 'Attachment test file exist' { - $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) - $FileName = "{0}.txt" -f 'GetServiceNowAttachment' - $newItemSplat = @{ - Name = $FileName - ItemType = 'File' - Value = $FileValue - } - $Script:File = New-Item @newItemSplat - - $File.FullName | Should -Exist - } - - It "File is attached to $($TestTicket.Number)" { - $addServiceNowAttachmentSplat = @{ - Number = $TestTicket.Number - Table = 'incident' - File = $File.FullName - Credential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL - PassThru = $true - } - $Script:Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat - - $Attachment.file_name | Should -Be $File.Name - } - - It 'Attachment test file removed' { - Remove-Item $File.FullName -Force - - $File.FullName | Should -Not -Exist - } - - It 'Attachment detail works' { - $getServiceNowAttachmentDetailSplat = @{ - Number = $TestTicket.Number - Table = 'incident' - FileName = $Attachment.file_name - Credential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL - } - $AttachmentDetail = Get-ServiceNowAttachmentDetail @getServiceNowAttachmentDetailSplat - - $AttachmentDetail.sys_id | Should -Be $Attachment.sys_id - } -} - -<# - -$Hash = @{ - Path = 'C:\Users\1113193\OneDrive\GitHub\servicenow-powershell\Tests\GetServiceNowAttachmentDetail.Tests.ps1' - Parameters = @{ - Credential = $Credential - } -} - -$invokePesterSplat = @{ - Script = $Hash - Tag = 'Attachment' -} -Invoke-Pester @invokePesterSplat - -#> From f895df03b1875c2a95ee723eab75b45319278d4f Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Thu, 14 Feb 2019 15:56:53 -0600 Subject: [PATCH 157/348] ReAdd Attachment Function Pester Tests --- Tests/AddServiceNowAttachment.Tests.ps1 | 96 ++++++++++++++ Tests/GetServiceNowAttachment.Tests.ps1 | 119 ++++++++++++++++++ Tests/GetServiceNowAttachmentDetail.Tests.ps1 | 109 ++++++++++++++++ 3 files changed, 324 insertions(+) create mode 100644 Tests/AddServiceNowAttachment.Tests.ps1 create mode 100644 Tests/GetServiceNowAttachment.Tests.ps1 create mode 100644 Tests/GetServiceNowAttachmentDetail.Tests.ps1 diff --git a/Tests/AddServiceNowAttachment.Tests.ps1 b/Tests/AddServiceNowAttachment.Tests.ps1 new file mode 100644 index 0000000..806e7f2 --- /dev/null +++ b/Tests/AddServiceNowAttachment.Tests.ps1 @@ -0,0 +1,96 @@ +[CmdletBinding()] +Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullorEmpty()] + [PSCredential]$Credential +) + +If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} +$Script:ThisCommand = $MyInvocation.MyCommand + +$ProjectRoot = Resolve-Path "$PSScriptRoot\.." +$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") +$ModuleName = Split-Path $ModuleRoot -Leaf +$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path +$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path +$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +$ModuleLoaded = Get-Module $ModuleName +If ($null -eq $ModuleLoaded) { + Import-Module $ModulePSD -Force +} +ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { + Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue + Import-Module $ModulePSD -Force +} + +# Load defaults from file +If (Test-Path $DefaultsFile) { + $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json + + If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { + Throw 'Please populate the *.Pester.Defaults.json file with your values' + } +} +Else { + # Write example file + @{ + ServiceNowURL = 'testingurl.service-now.com' + TestCategory = 'Internal' + TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' + TestUser = '6816f79cc0a8016401c5a33be04be441' + } | ConvertTo-Json | Set-Content $DefaultsFile + Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" +} + +Describe "$ThisCommand" -Tag Attachment { + # It "Test It" {} + + It "Create incident with New-ServiceNowIncident" { + $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + Comment = 'Test Comment' + ServiceNowCredential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should -Be $ShortDescription + } + + It 'Attachment test file exist' { + $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) + $FileName = "{0}.txt" -f 'GetServiceNowAttachment' + $newItemSplat = @{ + Name = $FileName + ItemType = 'File' + Value = $FileValue + } + $Script:File = New-Item @newItemSplat + + $File.FullName | Should -Exist + } + + It "File is attached to $($TestTicket.Number)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + PassThru = $true + } + $Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It 'Attachment test file removed' { + Remove-Item $File.FullName -Force + + $File.FullName | Should -Not -Exist + } +} diff --git a/Tests/GetServiceNowAttachment.Tests.ps1 b/Tests/GetServiceNowAttachment.Tests.ps1 new file mode 100644 index 0000000..4f90178 --- /dev/null +++ b/Tests/GetServiceNowAttachment.Tests.ps1 @@ -0,0 +1,119 @@ +[CmdletBinding()] +Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullorEmpty()] + [PSCredential]$Credential +) + +If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} +$Script:ThisCommand = $MyInvocation.MyCommand + +$ProjectRoot = Resolve-Path "$PSScriptRoot\.." +$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") +$ModuleName = Split-Path $ModuleRoot -Leaf +$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path +$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path +$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +$ModuleLoaded = Get-Module $ModuleName +If ($null -eq $ModuleLoaded) { + Import-Module $ModulePSD -Force +} +ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { + Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue + Import-Module $ModulePSD -Force +} + +# Load defaults from file +If (Test-Path $DefaultsFile) { + $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json + + If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { + Throw 'Please populate the *.Pester.Defaults.json file with your values' + } +} +Else { + # Write example file + @{ + ServiceNowURL = 'testingurl.service-now.com' + TestCategory = 'Internal' + TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' + TestUser = '6816f79cc0a8016401c5a33be04be441' + } | ConvertTo-Json | Set-Content $DefaultsFile + Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" +} + +Describe "$ThisCommand" -Tag Attachment { + # It "Test It" {} + + It "Create incident with New-ServiceNowIncident" { + $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + Comment = 'Test Comment' + ServiceNowCredential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should -Be $ShortDescription + } + + It 'Attachment test file exist' { + $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) + $FileName = "{0}.txt" -f 'GetServiceNowAttachment' + $newItemSplat = @{ + Name = $FileName + ItemType = 'File' + Value = $FileValue + } + $Script:File = New-Item @newItemSplat + + $File.FullName | Should -Exist + } + + It "File is attached to $($TestTicket.Number)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + PassThru = $true + } + $Script:Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It 'Attachment test file removed' { + Remove-Item $File.FullName -Force + + $File.FullName | Should -Not -Exist + } + + It 'Attachment downloaded successfully' { + $FileName = 'DownloadServiceNowAttachment.txt' + $Script:ExpectedOutput = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), + $Attachment.sys_id,[io.path]::GetExtension($FileName) + + $getServiceNowAttachmentSplat = @{ + FileName = $FileName + SysId = $Attachment.sys_id + AppendNameWithSysID = $true + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + Get-ServiceNowAttachment @getServiceNowAttachmentSplat + + $ExpectedOutput | Should -Exist + } + + It 'Attachment test file removed' { + Remove-Item $ExpectedOutput -Force + + $ExpectedOutput | Should -Not -Exist + } +} diff --git a/Tests/GetServiceNowAttachmentDetail.Tests.ps1 b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 new file mode 100644 index 0000000..70f23ed --- /dev/null +++ b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 @@ -0,0 +1,109 @@ +[CmdletBinding()] +Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullorEmpty()] + [PSCredential]$Credential +) + +If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} +$Script:ThisCommand = $MyInvocation.MyCommand + +$ProjectRoot = Resolve-Path "$PSScriptRoot\.." +$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") +$ModuleName = Split-Path $ModuleRoot -Leaf +$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path +$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path +$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +$ModuleLoaded = Get-Module $ModuleName +If ($null -eq $ModuleLoaded) { + Import-Module $ModulePSD -Force +} +ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { + Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue + Import-Module $ModulePSD -Force +} + +# Load defaults from file +If (Test-Path $DefaultsFile) { + $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json + + If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { + Throw 'Please populate the *.Pester.Defaults.json file with your values' + } +} +Else { + # Write example file + @{ + ServiceNowURL = 'testingurl.service-now.com' + TestCategory = 'Internal' + TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' + TestUser = '6816f79cc0a8016401c5a33be04be441' + } | ConvertTo-Json | Set-Content $DefaultsFile + Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" +} + +Describe "$ThisCommand" -Tag Attachment { + # It "Test It" {} + + It "Create incident with New-ServiceNowIncident" { + $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + Comment = 'Test Comment' + ServiceNowCredential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should -Be $ShortDescription + } + + It 'Attachment test file exist' { + $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) + $FileName = "{0}.txt" -f 'GetServiceNowAttachment' + $newItemSplat = @{ + Name = $FileName + ItemType = 'File' + Value = $FileValue + } + $Script:File = New-Item @newItemSplat + + $File.FullName | Should -Exist + } + + It "File is attached to $($TestTicket.Number)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + PassThru = $true + } + $Script:Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It 'Attachment test file removed' { + Remove-Item $File.FullName -Force + + $File.FullName | Should -Not -Exist + } + + It 'Attachment detail works' { + $getServiceNowAttachmentDetailSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + FileName = $Attachment.file_name + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + $AttachmentDetail = Get-ServiceNowAttachmentDetail @getServiceNowAttachmentDetailSplat + + $AttachmentDetail.sys_id | Should -Be $Attachment.sys_id + } +} From 7a1330d0d48b44b05128d5de1f44793de13985d6 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 15 Feb 2019 14:03:37 -0600 Subject: [PATCH 158/348] Url alias & Url validation corrections --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 7 ++----- ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 1 + ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 | 7 ++----- ServiceNow/Public/Remove-ServiceNowAttachment.ps1 | 11 ++++++----- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index f1d267f..44ae261 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -72,6 +72,7 @@ Function Add-ServiceNowAttachment { [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] [ValidateScript({Test-ServiceNowURL -Url $_})] [ValidateNotNullOrEmpty()] + [Alias('Url')] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance @@ -104,11 +105,7 @@ Function Add-ServiceNowAttachment { $getServiceNowTableEntry.Add('Connection', $Connection) } Default { - If ((Test-ServiceNowAuthIsSet)) { - $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $Global:ServiceNowRESTURL - } - Else { + If (-not (Test-ServiceNowAuthIsSet)) { 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" } } diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 7d4f983..e02a5c5 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -90,6 +90,7 @@ Function Get-ServiceNowAttachment { [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] [ValidateScript({Test-ServiceNowURL -Url $_})] [ValidateNotNullOrEmpty()] + [Alias('Url')] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index ae71089..2a474a2 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -60,6 +60,7 @@ Function Get-ServiceNowAttachmentDetail { [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] [ValidateScript({Test-ServiceNowURL -Url $_})] [ValidateNotNullOrEmpty()] + [Alias('Url')] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance @@ -88,11 +89,7 @@ Function Get-ServiceNowAttachmentDetail { $getServiceNowTableEntry.Add('Connection', $Connection) } Default { - If ((Test-ServiceNowAuthIsSet)) { - $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $Global:ServiceNowRESTURL - } - Else { + If (-not (Test-ServiceNowAuthIsSet)) { 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" } } diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index 593cf1e..bbba4b0 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -43,6 +43,7 @@ Function Remove-ServiceNowAttachment { [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] [ValidateScript({Test-ServiceNowURL -Url $_})] [ValidateNotNullOrEmpty()] + [Alias('Url')] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance @@ -58,17 +59,17 @@ Function Remove-ServiceNowAttachment { # Process credential steps based on parameter set name Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' } Default { - If ((Test-ServiceNowAuthIsSet)) { + If (Test-ServiceNowAuthIsSet) { $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $Global:ServiceNowRESTURL + '/attachment' + $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' } 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" @@ -76,7 +77,7 @@ Function Remove-ServiceNowAttachment { } } - $Uri = $ServiceNowURL + '/' + $SysID + $Uri = $ApiUrl + '/' + $SysID Write-Verbose "URI: $Uri" $invokeRestMethodSplat = @{ From 2d098004eacb19f5017f4e309a8755c216c46430 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 15 Feb 2019 14:04:24 -0600 Subject: [PATCH 159/348] Attachment function Pester test edits --- Tests/AddServiceNowAttachment.Tests.ps1 | 35 +++++++++++------ Tests/GetServiceNowAttachment.Tests.ps1 | 38 +++++++++++++------ Tests/GetServiceNowAttachmentDetail.Tests.ps1 | 23 ++++++++--- 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/Tests/AddServiceNowAttachment.Tests.ps1 b/Tests/AddServiceNowAttachment.Tests.ps1 index 806e7f2..942add3 100644 --- a/Tests/AddServiceNowAttachment.Tests.ps1 +++ b/Tests/AddServiceNowAttachment.Tests.ps1 @@ -34,7 +34,7 @@ If (Test-Path $DefaultsFile) { } Else { # Write example file - @{ + @{ ServiceNowURL = 'testingurl.service-now.com' TestCategory = 'Internal' TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' @@ -44,25 +44,24 @@ Else { } Describe "$ThisCommand" -Tag Attachment { - # It "Test It" {} + + $null = Set-ServiceNowAuth -Url $Defaults.ServiceNowUrl -Credentials $Credential It "Create incident with New-ServiceNowIncident" { $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" $newServiceNowIncidentSplat = @{ - Caller = $Defaults.TestUser - ShortDescription = $ShortDescription - Description = 'Long description' - Comment = 'Test Comment' - ServiceNowCredential = $Credential - ServiceNowURL = $Defaults.ServiceNowURL + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + Comment = 'Test Comment' } - $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + {$Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat} | Should -Not -Throw $TestTicket.short_description | Should -Be $ShortDescription } It 'Attachment test file exist' { - $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) + $FileValue = "{0}`t{1}" -f (Get-Date), $ThisCommand $FileName = "{0}.txt" -f 'GetServiceNowAttachment' $newItemSplat = @{ Name = $FileName @@ -74,7 +73,19 @@ Describe "$ThisCommand" -Tag Attachment { $File.FullName | Should -Exist } - It "File is attached to $($TestTicket.Number)" { + It "File is attached to $($TestTicket.Number) (Global Credentials)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + PassThru = $true + } + $Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It "File is attached to $($TestTicket.Number) (Specified Credentials)" { $addServiceNowAttachmentSplat = @{ Number = $TestTicket.Number Table = 'incident' @@ -93,4 +104,6 @@ Describe "$ThisCommand" -Tag Attachment { $File.FullName | Should -Not -Exist } + + $null = Remove-ServiceNowAuth } diff --git a/Tests/GetServiceNowAttachment.Tests.ps1 b/Tests/GetServiceNowAttachment.Tests.ps1 index 4f90178..d62b29a 100644 --- a/Tests/GetServiceNowAttachment.Tests.ps1 +++ b/Tests/GetServiceNowAttachment.Tests.ps1 @@ -34,7 +34,7 @@ If (Test-Path $DefaultsFile) { } Else { # Write example file - @{ + @{ ServiceNowURL = 'testingurl.service-now.com' TestCategory = 'Internal' TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' @@ -44,7 +44,7 @@ Else { } Describe "$ThisCommand" -Tag Attachment { - # It "Test It" {} + $null = Set-ServiceNowAuth -Url $Defaults.ServiceNowUrl -Credentials $Credential It "Create incident with New-ServiceNowIncident" { $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" @@ -62,8 +62,8 @@ Describe "$ThisCommand" -Tag Attachment { } It 'Attachment test file exist' { - $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) - $FileName = "{0}.txt" -f 'GetServiceNowAttachment' + $FileValue = "{0}`t{1}" -f (Get-Date), $ThisCommand + $FileName = "{0}.txt" -f ('GetServiceNowAttachment') $newItemSplat = @{ Name = $FileName ItemType = 'File' @@ -94,26 +94,42 @@ Describe "$ThisCommand" -Tag Attachment { $File.FullName | Should -Not -Exist } - It 'Attachment downloaded successfully' { - $FileName = 'DownloadServiceNowAttachment.txt' - $Script:ExpectedOutput = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), - $Attachment.sys_id,[io.path]::GetExtension($FileName) + $Script:FileName = 'DownloadServiceNowAttachment.txt' + $Script:ExpectedOutput = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName),$Attachment.sys_id, [io.path]::GetExtension($FileName) + It 'Attachment download successful (Global Credentials, Append Name)' { $getServiceNowAttachmentSplat = @{ FileName = $FileName SysId = $Attachment.sys_id AppendNameWithSysID = $true + } + {Get-ServiceNowAttachment @getServiceNowAttachmentSplat} | Should -Not -Throw + $ExpectedOutput | Should -Exist + } + + It 'Attachment download successful (Specify Credentials, Allow Overwrite)' { + $getServiceNowAttachmentSplat = @{ + FileName = $FileName + SysId = $Attachment.sys_id + AppendNameWithSysID = $true + AllowOverwrite = $true Credential = $Credential ServiceNowURL = $Defaults.ServiceNowURL } - Get-ServiceNowAttachment @getServiceNowAttachmentSplat - $ExpectedOutput | Should -Exist + {Get-ServiceNowAttachment @getServiceNowAttachmentSplat} | Should -Not -Throw } It 'Attachment test file removed' { - Remove-Item $ExpectedOutput -Force + Try { + Remove-Item $ExpectedOutput -Force -ErrorAction Stop + } + Catch { + Write-Error $PSItem + } $ExpectedOutput | Should -Not -Exist } + + $null = Remove-ServiceNowAuth } diff --git a/Tests/GetServiceNowAttachmentDetail.Tests.ps1 b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 index 70f23ed..3b67e13 100644 --- a/Tests/GetServiceNowAttachmentDetail.Tests.ps1 +++ b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 @@ -44,7 +44,7 @@ Else { } Describe "$ThisCommand" -Tag Attachment { - # It "Test It" {} + $null = Set-ServiceNowAuth -Url $Defaults.ServiceNowUrl -Credentials $Credential It "Create incident with New-ServiceNowIncident" { $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" @@ -62,7 +62,7 @@ Describe "$ThisCommand" -Tag Attachment { } It 'Attachment test file exist' { - $FileValue = "{0}`t{1}" -f (Get-Date),$($MyInvocation.MyCommand) + $FileValue = "{0}`t{1}" -f (Get-Date), $ThisCommand $FileName = "{0}.txt" -f 'GetServiceNowAttachment' $newItemSplat = @{ Name = $FileName @@ -94,11 +94,22 @@ Describe "$ThisCommand" -Tag Attachment { $File.FullName | Should -Not -Exist } - It 'Attachment detail works' { + It 'Attachment detail works (Global Credentials)' { $getServiceNowAttachmentDetailSplat = @{ - Number = $TestTicket.Number - Table = 'incident' + Number = $TestTicket.Number + Table = 'incident' FileName = $Attachment.file_name + } + $AttachmentDetail = Get-ServiceNowAttachmentDetail @getServiceNowAttachmentDetailSplat + + $AttachmentDetail.sys_id | Should -Be $Attachment.sys_id + } + + It 'Attachment detail works (Specify Credentials)' { + $getServiceNowAttachmentDetailSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + FileName = $Attachment.file_name Credential = $Credential ServiceNowURL = $Defaults.ServiceNowURL } @@ -106,4 +117,6 @@ Describe "$ThisCommand" -Tag Attachment { $AttachmentDetail.sys_id | Should -Be $Attachment.sys_id } + + $null = Remove-ServiceNowAuth } From acb294dccc17b7c7d02e09def26db919071e6515 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 15 Feb 2019 14:04:56 -0600 Subject: [PATCH 160/348] Add remove attachment function Pester test --- Tests/RemoveServiceNowAttachment.Tests.ps1 | 126 +++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 Tests/RemoveServiceNowAttachment.Tests.ps1 diff --git a/Tests/RemoveServiceNowAttachment.Tests.ps1 b/Tests/RemoveServiceNowAttachment.Tests.ps1 new file mode 100644 index 0000000..9512d76 --- /dev/null +++ b/Tests/RemoveServiceNowAttachment.Tests.ps1 @@ -0,0 +1,126 @@ +[CmdletBinding()] +Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullorEmpty()] + [PSCredential]$Credential +) + +If (-not $PSScriptRoot) {$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent} +$Script:ThisCommand = $MyInvocation.MyCommand + +$ProjectRoot = Resolve-Path "$PSScriptRoot\.." +$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") +$ModuleName = Split-Path $ModuleRoot -Leaf +$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path +$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path +$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +$ModuleLoaded = Get-Module $ModuleName +If ($null -eq $ModuleLoaded) { + Import-Module $ModulePSD -Force +} +ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { + Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue + Import-Module $ModulePSD -Force +} + +# Load defaults from file +If (Test-Path $DefaultsFile) { + $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json + + If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { + Throw 'Please populate the *.Pester.Defaults.json file with your values' + } +} +Else { + # Write example file + @{ + ServiceNowURL = 'testingurl.service-now.com' + TestCategory = 'Internal' + TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' + TestUser = '6816f79cc0a8016401c5a33be04be441' + } | ConvertTo-Json | Set-Content $DefaultsFile + Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" +} + +Describe "$ThisCommand" -Tag Attachment { + $null = Set-ServiceNowAuth -Url $Defaults.ServiceNowUrl -Credentials $Credential + + It "Create incident with New-ServiceNowIncident" { + $ShortDescription = "Testing Ticket Creation with Pester: $ThisCommand" + $newServiceNowIncidentSplat = @{ + Caller = $Defaults.TestUser + ShortDescription = $ShortDescription + Description = 'Long description' + Comment = 'Test Comment' + } + $Script:TestTicket = New-ServiceNowIncident @newServiceNowIncidentSplat + + $TestTicket.short_description | Should -Be $ShortDescription + } + + It 'Attachment test file exist' { + $FileValue = "{0}`t{1}" -f (Get-Date), $ThisCommand + $FileName = "{0}.txt" -f 'GetServiceNowAttachment' + $newItemSplat = @{ + Name = $FileName + ItemType = 'File' + Value = $FileValue + } + $Script:File = New-Item @newItemSplat + + $File.FullName | Should -Exist + } + + It "File is attached to $($TestTicket.Number) (Global Credentials)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + PassThru = $true + } + $Script:Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It "File is removed from $($TestTicket.Number) (Global Credentials)" { + {$Attachment | Remove-ServiceNowAttachment} | Should -Not -Throw + + $AttachmentDetail = Get-ServiceNowAttachmentDetail -Number $TestTicket.Number -Table 'incident' + + $AttachmentDetail | Should -Be $null + } + + It "File is attached to $($TestTicket.Number) (Specify Credentials)" { + $addServiceNowAttachmentSplat = @{ + Number = $TestTicket.Number + Table = 'incident' + File = $File.FullName + PassThru = $true + } + $Script:Attachment = Add-ServiceNowAttachment @addServiceNowAttachmentSplat + + $Attachment.file_name | Should -Be $File.Name + } + + It "File is removed from $($TestTicket.Number) (Specify Credentials)" { + $removeServiceNowAttachmentSplat = @{ + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + } + {$Attachment | Remove-ServiceNowAttachment @removeServiceNowAttachmentSplat} | Should -Not -Throw + + $AttachmentDetail = Get-ServiceNowAttachmentDetail -Number $TestTicket.Number -Table 'incident' + + $AttachmentDetail | Should -Be $null + } + + It 'Attachment test file removed' { + Remove-Item $File.FullName -Force + + $File.FullName | Should -Not -Exist + } + + $null = Remove-ServiceNowAuth +} From 3bb76e9f58347c5214227b1ae4540fc5234b6dbb Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Fri, 15 Feb 2019 14:05:34 -0600 Subject: [PATCH 161/348] Adjust psake & ServiceNow.Tests.ps1 to support other test files --- Build/psake.ps1 | 27 +++++++++++++--- Tests/ServiceNow.Tests.ps1 | 63 +++++++++++++++++++++----------------- 2 files changed, 58 insertions(+), 32 deletions(-) diff --git a/Build/psake.ps1 b/Build/psake.ps1 index c60b3c6..070eda1 100644 --- a/Build/psake.ps1 +++ b/Build/psake.ps1 @@ -7,8 +7,7 @@ Properties { $ProjectRoot = Resolve-Path "$PSScriptRoot\.." } - # - $StepVersionBy = 'Build' + $StepVersionBy = $null $Timestamp = Get-date -uformat "%Y%m%d-%H%M%S" $PSVersion = $PSVersionTable.PSVersion.Major @@ -60,7 +59,21 @@ Task Test -Depends UnitTests { $CodeFiles = Get-ChildItem $ENV:BHModulePath -Recurse -Include "*.psm1","*.ps1" $CodeCoverage = New-Object System.Collections.ArrayList $CodeCoverage.AddRange($CodeFiles.FullName) - $Script:TestResults = Invoke-Pester -Path $ProjectRoot\Tests -CodeCoverage $CodeCoverage -PassThru -OutputFormat NUnitXml -OutputFile $TestFilePath + $Credential = Get-Credential + $invokePesterScript = @{ + Path = "$ProjectRoot\Tests" + Parameters = @{ + Credential = $Credential + } + } + $invokePesterSplat = @{ + Script = $invokePesterScript + CodeCoverage = $CodeCoverage + OutputFile = $TestFilePath + OutputFormat = 'NUnitXml' + PassThru = $true + } + $Script:TestResults = Invoke-Pester @invokePesterSplat [xml]$content = Get-Content $TestFilePath $content.'test-results'.'test-suite'.type = "Powershell" @@ -94,7 +107,13 @@ Task Build -Depends Test { Set-ModuleFunctions -Name $env:BHPSModuleManifest -FunctionsToExport $functions # Bump the module version - $version = [version] (Step-Version -Version (Get-Metadata -Path $env:BHPSModuleManifest) -By $StepVersionBy) + $stepVersionSplat = @{ + Version = (Get-Metadata -Path $env:BHPSModuleManifest) + } + If ($null -ne $StepVersionBy) { + $stepVersionSplat.Add('By',$StepVersionBy) + } + $version = [version](Step-Version @stepVersionSplat) $galleryVersion = Get-NextPSGalleryVersion -Name $env:BHProjectName if($version -lt $galleryVersion) { diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index 4258295..36fc8e0 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -1,38 +1,45 @@ -$projectRoot = Resolve-Path "$PSScriptRoot\.." -$moduleRoot = Split-Path (Resolve-Path "$projectRoot\*\*.psd1") -$moduleName = Split-Path $moduleRoot -Leaf -$DefaultsFile = Join-Path $projectRoot "Tests\$($ModuleName).Pester.Defaults.json" +[CmdletBinding()] +Param( + [Parameter(Mandatory = $true)] + [ValidateNotNullorEmpty()] + [PSCredential]$Credential +) + +$ProjectRoot = Resolve-Path "$PSScriptRoot\.." +$ModuleRoot = Split-Path (Resolve-Path "$ProjectRoot\*\*.psd1") +$ModuleName = Split-Path $ModuleRoot -Leaf +$ModulePsd = (Resolve-Path "$ProjectRoot\*\$ModuleName.psd1").Path +$ModulePsm = (Resolve-Path "$ProjectRoot\*\$ModuleName.psm1").Path +$DefaultsFile = Join-Path $ProjectRoot "Tests\$($ModuleName).Pester.Defaults.json" + +$ModuleLoaded = Get-Module $ModuleName +If ($null -eq $ModuleLoaded) { + Import-Module $ModulePSD -Force +} +ElseIf ($null -ne $ModuleLoaded -and $ModuleLoaded -ne $ModulePSM) { + Remove-Module $ModuleName -Force -ErrorAction SilentlyContinue + Import-Module $ModulePSD -Force +} # Load defaults from file -if (Test-Path $DefaultsFile) { - $Defaults = @{} - # Add properties to the defaults hash - (Get-Content $DefaultsFile | Out-String | ConvertFrom-Json).psobject.properties | ForEach-Object { - $Defaults."$($_.Name)" = $_.Value - } +If (Test-Path $DefaultsFile) { + $Script:Defaults = Get-Content $DefaultsFile -Raw | ConvertFrom-Json - # Prompt for credentials - $Defaults.Creds = if ($Defaults.Creds) { - $Defaults.Creds - } else { - Get-Credential + If ('testingurl.service-now.com' -eq $Defaults.ServiceNowUrl) { + Throw 'Please populate the *.Pester.Defaults.json file with your values' } -} else { +} +Else { # Write example file - @{ + @{ ServiceNowURL = 'testingurl.service-now.com' TestCategory = 'Internal' - TestUserGroup = 'e9e9a2406f4c35001855fa0dba3ee4f3' - TestUser = "7a4b573a6f3725001855fa0dba3ee485" + TestUserGroup = '8a4dde73c6112278017a6a4baf547aa7' + TestUser = '6816f79cc0a8016401c5a33be04be441' } | ConvertTo-Json | Set-Content $DefaultsFile - Write-Error "$DefaultsFile does not exist. Created example file. Please populate with your values" - Return + Throw "$DefaultsFile does not exist. Created example file. Please populate with your values" } -# Load the module (unload it first in case we've made changes since loading it previously) -Remove-Module $ModuleName -ErrorAction SilentlyContinue -Import-Module (Join-Path $moduleRoot "$moduleName.psd1") -Force - Describe "ServiceNow-Module" { # Ensure auth is not set (not a test) If (Test-ServiceNowAuthisSet) { @@ -50,7 +57,7 @@ Describe "ServiceNow-Module" { } It "Set-ServiceNowAuth works" { - Set-ServiceNowAuth -url $Defaults.ServiceNowURL -Credentials $Defaults.Creds | Should -Be $true + Set-ServiceNowAuth -url $Defaults.ServiceNowURL -Credentials $Credential | Should -Be $true } It "Test-ServiceNowAuthIsSet set" { @@ -66,7 +73,7 @@ Describe "ServiceNow-Module" { $getServiceNowTableSplat = @{ Table = 'incident' Query = 'ORDERBYDESCopened_at' - Credential = $Defaults.Creds + Credential = $Credential ServiceNowURL = $Defaults.ServiceNowURL } ([array](Get-ServiceNowTable @getServiceNowTableSplat)).Count -gt 0 | Should -Match $true @@ -236,7 +243,7 @@ Describe "ServiceNow-Module" { Number = $TestTicket.Number Table = 'incident' Values = $Values - Credential = $Defaults.Creds + Credential = $Credential ServiceNowURL = $Defaults.ServiceNowURL } Update-ServiceNowNumber @updateServiceNowNumberSplat From d3bc24f53ab1c1107aed351e40f6c74cf4a867e8 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Wed, 20 Feb 2019 11:27:19 -0600 Subject: [PATCH 162/348] Incremented ModuleVersion to 1.6.0 --- ServiceNow/ServiceNow.psd1 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index edf0d47..18aa18e 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.5.3' +ModuleVersion = '1.6.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Remove-ServiceNowAttachment') +FunctionsToExport = @('Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() @@ -124,6 +124,8 @@ PrivateData = @{ + + From a9a94b040c325f463972b32165802bad27a84f3a Mon Sep 17 00:00:00 2001 From: mdejulia Date: Tue, 28 May 2019 15:03:08 -0700 Subject: [PATCH 163/348] New-ServiceNowChangeRequest.ps1 --- .../Public/New-ServiceNowChangeRequest.ps1 | 196 ++++++++++++++++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 ServiceNow/Public/New-ServiceNowChangeRequest.ps1 diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 new file mode 100644 index 0000000..3cf9e18 --- /dev/null +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -0,0 +1,196 @@ +function New-ServiceNowChangeRequest{ +<# +.SYNOPSIS + Generates a new ServiceNow change request + +.DESCRIPTION + Generates a new ServiceNow change request using predefined or custom fields by invoking the ServiceNow API + +.PARAMETER Caller + sys_id of the caller of the change request (user Get-ServiceNowUser to retrieve this) + +.PARAMETER ShortDescription + Short description of the change request + +.PARAMETER Description + Long description of the change request + +.PARAMETER AssignmentGroup + sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) + +.PARAMETER Comment + Comment to include in the ticket + +.PARAMETER Category + Category of the change request (e.g. 'Network') + +.PARAMETER Subcategory + Subcategory of the change request (e.g. 'Network') + +.PARAMETER ConfigurationItem + sys_id of the configuration item of the change request + +.PARAMETER CustomFields + Custom fields as hashtable + +.PARAMETER ServiceNowCredential + Credential used to authenticate to ServiceNow + +.PARAMETER ServiceNowURL + The URL for the ServiceNow instance being used (eg: instancename.service-now.com) + +.PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + +.LINK + https://github.com/Sam-Martin/servicenow-powershell + +.EXAMPLE + Generate a basic change request attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. + New-ServiceNowchange request -Caller "UserName" -ShortDescription = "New PS change request" -Description = "This change request was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 + +.EXAMPLE + Generate an Change Request by "Splatting" all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow Instance): + + $ChangeRequestParams = @{Caller = "UserName" + ShortDescription = "New PS Change Request" + Description = "This change request was created from Powershell" + AssignmentGroup "ServiceDesk" + Comment "Inline Comment" + Category "Office" + Subcategory "Outlook" + ConfigurationItem UserPC1 + CustomFields = @{u_custom1 = "Custom Field Entry" + u_another_custom = "Related Test"} + } + New-ServiceNowChangeRequest @Params + #> + + Param( + [parameter(Mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Caller, + + [parameter(Mandatory=$true)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$ShortDescription, + + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Description, + + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$AssignmentGroup, + + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Comment, + + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Category, + + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$Subcategory, + + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [string]$ConfigurationItem, + + [parameter(mandatory=$false)] + [parameter(ParameterSetName='SpecifyConnectionFields')] + [parameter(ParameterSetName='UseConnectionObject')] + [parameter(ParameterSetName='SetGlobalAuth')] + [hashtable]$CustomFields, + + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [PSCredential]$ServiceNowCredential, + + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [string]$ServiceNowURL, + + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [ValidateNotNullOrEmpty()] + [Hashtable]$Connection + ) + + # Create a hash table of any defined parameters (not CustomFields) that have values + $DefinedChangeRequestParameters = @('AssignmentGroup','Caller','Category','Comment','ConfigurationItem','Description','ShortDescription','Subcategory') + $TableEntryValues = @{} + ForEach ($Parameter in $DefinedChangeRequestParameters) { + If ($null -ne $PSBoundParameters.$Parameter) { + # Turn the defined parameter name into the ServiceNow attribute name + $KeyToAdd = Switch ($Parameter) { + AssignmentGroup {'assignment_group'} + Caller {'caller_id'} + Category {'category'} + Comment {'comments'} + ConfigurationItem {'cmdb_ci'} + Description {'description'} + ShortDescription {'short_description'} + Subcategory {'subcategory'} + } + $TableEntryValues.Add($KeyToAdd,$PSBoundParameters.$Parameter) + } + } + + # Add CustomFields hash pairs to the Table Entry Values hash table + If ($null -ne $PSBoundParameters.CustomFields) { + $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { + If (($TableEntryValues.ContainsKey($Key) -eq $False)) { + # Add the unique entry to the table entry values hash table + $TableEntryValues.Add($Key,$CustomFields[$Key]) + } + Else { + # Capture the duplicate key name + $Key + } + } + } + + # Throw an error if duplicate fields were provided + If ($null -ne $DuplicateTableEntryValues) { + $DuplicateKeyList = $DuplicateTableEntryValues -join "," + Throw "Ticket fields may only be used once: $DuplicateKeyList" + } + + # Table Entry Splat + $newServiceNowTableEntrySplat = @{ + Table = 'change_request' + Values = $TableEntryValues + } + + # Update the splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $newServiceNowTableEntrySplat.Add('Connection',$Connection) + } + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + { + $newServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) + $newServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) + } + + # Create the table entry + New-ServiceNowTableEntry @newServiceNowTableEntrySplat +} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 18aa18e..35526b2 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') +FunctionsToExport = @('Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From c0bdc52d84565aae5091ecd07bcabba476c512f0 Mon Sep 17 00:00:00 2001 From: mdejulia Date: Fri, 14 Jun 2019 15:52:43 -0700 Subject: [PATCH 164/348] New-ServiceNowChangeRequest, implemented the requested changes --- .../Public/New-ServiceNowChangeRequest.ps1 | 347 +++++++++--------- 1 file changed, 173 insertions(+), 174 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index 3cf9e18..5d0f2c1 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -1,196 +1,195 @@ -function New-ServiceNowChangeRequest{ -<# -.SYNOPSIS - Generates a new ServiceNow change request - -.DESCRIPTION - Generates a new ServiceNow change request using predefined or custom fields by invoking the ServiceNow API - -.PARAMETER Caller - sys_id of the caller of the change request (user Get-ServiceNowUser to retrieve this) - -.PARAMETER ShortDescription - Short description of the change request - -.PARAMETER Description - Long description of the change request - -.PARAMETER AssignmentGroup - sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) - -.PARAMETER Comment - Comment to include in the ticket - -.PARAMETER Category - Category of the change request (e.g. 'Network') - -.PARAMETER Subcategory - Subcategory of the change request (e.g. 'Network') - -.PARAMETER ConfigurationItem - sys_id of the configuration item of the change request - -.PARAMETER CustomFields - Custom fields as hashtable - -.PARAMETER ServiceNowCredential - Credential used to authenticate to ServiceNow - -.PARAMETER ServiceNowURL - The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - -.PARAMETER Connection - Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - -.LINK - https://github.com/Sam-Martin/servicenow-powershell - -.EXAMPLE - Generate a basic change request attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. - New-ServiceNowchange request -Caller "UserName" -ShortDescription = "New PS change request" -Description = "This change request was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 - -.EXAMPLE - Generate an Change Request by "Splatting" all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow Instance): - - $ChangeRequestParams = @{Caller = "UserName" - ShortDescription = "New PS Change Request" - Description = "This change request was created from Powershell" - AssignmentGroup "ServiceDesk" - Comment "Inline Comment" - Category "Office" - Subcategory "Outlook" - ConfigurationItem UserPC1 - CustomFields = @{u_custom1 = "Custom Field Entry" - u_another_custom = "Related Test"} +function New-ServiceNowChangeRequest { + <# + .SYNOPSIS + Generates a new ServiceNow change request + + .DESCRIPTION + Generates a new ServiceNow change request using predefined or custom fields by invoking the ServiceNow API + + .PARAMETER Caller + sys_id of the caller of the change request (user Get-ServiceNowUser to retrieve this) + + .PARAMETER ShortDescription + Short description of the change request + + .PARAMETER Description + Long description of the change request + + .PARAMETER AssignmentGroup + sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) + + .PARAMETER Comment + Comment to include in the ticket + + .PARAMETER Category + Category of the change request (e.g. 'Network') + + .PARAMETER Subcategory + Subcategory of the change request (e.g. 'Network') + + .PARAMETER ConfigurationItem + sys_id of the configuration item of the change request + + .PARAMETER CustomFields + Custom fields as hashtable + + .PARAMETER ServiceNowCredential + Credential used to authenticate to ServiceNow + + .PARAMETER ServiceNowURL + The URL for the ServiceNow instance being used (eg: instancename.service-now.com) + + .PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + + .PARAMETER PassThru + Returns the ticket values after creation + + .LINK + https://github.com/Sam-Martin/servicenow-powershell + + .EXAMPLE + Generate a basic change request attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. + + New-ServiceNowchange request -Caller UserName -ShortDescription 'New PS change request' -Description 'This change request was created from Powershell' -AssignmentGroup ServiceDesk -Comment 'Inline Comment' -Category Office -Subcategory Outlook -ConfigurationItem UserPC1 + + .EXAMPLE + Generate an Change Request by 'splatting' all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow instance), This example uses the caller's sys_id value for identification. + + $newServiceNowChangeRequestSplat = @{ + Caller = '55ccf91161924edc979d8e7e5627a47d' + ShortDescription = 'New PS Change Request' + Description = 'This change request was created from Powershell' + AssignmentGroup = 'ServiceDesk' + Comment = 'Inline Comment' + Category = 'Office' + Subcategory = 'Outlook' + ConfigurationItem = 'UserPC1' + CustomFields = @{ + u_custom1 = 'Custom Field Entry' + u_another_custom = 'Related Test' } - New-ServiceNowChangeRequest @Params - #> - + } + New-ServiceNowChangeRequest @newServiceNowChangeRequestSplat + #> + + [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess)] Param( - [parameter(Mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter(Mandatory = $true)] [string]$Caller, - - [parameter(Mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + + [parameter(Mandatory = $true)] [string]$ShortDescription, - - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + + [parameter(Mandatory = $false)] [string]$Description, - - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + + [parameter(Mandatory = $false)] [string]$AssignmentGroup, - - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + + [parameter(Mandatory = $false)] [string]$Comment, - - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + + [parameter(Mandatory = $false)] [string]$Category, - - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + + [parameter(Mandatory = $false)] [string]$Subcategory, - - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + + [parameter(Mandatory = $false)] [string]$ConfigurationItem, - - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + + [parameter(Mandatory = $false)] [hashtable]$CustomFields, - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] [PSCredential]$ServiceNowCredential, - - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, - - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection + [Hashtable]$Connection, + + # Switch to allow the results to be passed back + [Parameter(Mandatory = $false)] + [switch]$PassThru ) - - # Create a hash table of any defined parameters (not CustomFields) that have values - $DefinedChangeRequestParameters = @('AssignmentGroup','Caller','Category','Comment','ConfigurationItem','Description','ShortDescription','Subcategory') - $TableEntryValues = @{} - ForEach ($Parameter in $DefinedChangeRequestParameters) { - If ($null -ne $PSBoundParameters.$Parameter) { - # Turn the defined parameter name into the ServiceNow attribute name - $KeyToAdd = Switch ($Parameter) { - AssignmentGroup {'assignment_group'} - Caller {'caller_id'} - Category {'category'} - Comment {'comments'} - ConfigurationItem {'cmdb_ci'} - Description {'description'} - ShortDescription {'short_description'} - Subcategory {'subcategory'} + + begin { } + process { + Try { + # Create a hash table of any defined parameters (not CustomFields) that have values + $DefinedChangeRequestParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') + $TableEntryValues = @{ } + ForEach ($Parameter in $DefinedChangeRequestParameters) { + If ($null -ne $PSBoundParameters.$Parameter) { + # Turn the defined parameter name into the ServiceNow attribute name + $KeyToAdd = Switch ($Parameter) { + AssignmentGroup { 'assignment_group' } + Caller { 'caller_id' } + Category { 'category' } + Comment { 'comments' } + ConfigurationItem { 'cmdb_ci' } + Description { 'description' } + ShortDescription { 'short_description' } + Subcategory { 'subcategory' } + } + $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) + } } - $TableEntryValues.Add($KeyToAdd,$PSBoundParameters.$Parameter) - } - } - - # Add CustomFields hash pairs to the Table Entry Values hash table - If ($null -ne $PSBoundParameters.CustomFields) { - $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { - If (($TableEntryValues.ContainsKey($Key) -eq $False)) { - # Add the unique entry to the table entry values hash table - $TableEntryValues.Add($Key,$CustomFields[$Key]) + + # Add CustomFields hash pairs to the Table Entry Values hash table + If ($null -ne $PSBoundParameters.CustomFields) { + $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { + If (($TableEntryValues.ContainsKey($Key) -eq $False)) { + # Add the unique entry to the table entry values hash table + $TableEntryValues.Add($Key, $CustomFields[$Key]) + } + Else { + # Capture the duplicate key name + $Key + } + } + } + + # Throw an error if duplicate fields were provided + If ($null -ne $DuplicateTableEntryValues) { + $DuplicateKeyList = $DuplicateTableEntryValues -join "," + Throw "Ticket fields may only be used once: $DuplicateKeyList" + } + + # Table Entry Splat + $newServiceNowTableEntrySplat = @{ + Table = 'change_request' + Values = $TableEntryValues + } + + # Update the splat if the parameters have values + If ($null -ne $PSBoundParameters.Connection) { + $newServiceNowTableEntrySplat.Add('Connection', $Connection) } - Else { - # Capture the duplicate key name - $Key + ElseIf ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { + $newServiceNowTableEntrySplat.Add('ServiceNowCredential', $ServiceNowCredential) + $newServiceNowTableEntrySplat.Add('ServiceNowURL', $ServiceNowURL) + } + + # Create the table entry + If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { + $Result = New-ServiceNowTableEntry @newServiceNowTableEntrySplat + + # Option to return results + If ($PSBoundParameters.ContainsKey('Passthru')) { + $Result + } } } + Catch { + Write-Error $PSItem + } } - - # Throw an error if duplicate fields were provided - If ($null -ne $DuplicateTableEntryValues) { - $DuplicateKeyList = $DuplicateTableEntryValues -join "," - Throw "Ticket fields may only be used once: $DuplicateKeyList" - } - - # Table Entry Splat - $newServiceNowTableEntrySplat = @{ - Table = 'change_request' - Values = $TableEntryValues - } - - # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { - $newServiceNowTableEntrySplat.Add('Connection',$Connection) - } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { - $newServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) - $newServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) - } - - # Create the table entry - New-ServiceNowTableEntry @newServiceNowTableEntrySplat -} + end { } +} \ No newline at end of file From f2c0cee761f359802a593a63f0575bde13cc6750 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 18 Jun 2019 14:32:07 -0500 Subject: [PATCH 165/348] v1.7.0 - Added New-ServiceNowChangeRequest --- Readme.md | 2 +- ServiceNow/ServiceNow.psd1 | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 6545d4a..8be8943 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-79%25-yellow.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-75%25-yellow.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. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 35526b2..e74e05f 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.6.0' +ModuleVersion = '1.7.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -126,6 +126,8 @@ PrivateData = @{ + + From 92cab48e03df9160782492d7188ee023e0d01044 Mon Sep 17 00:00:00 2001 From: mdejulia Date: Mon, 1 Jul 2019 11:30:26 -0700 Subject: [PATCH 166/348] break swtiches --- .../Public/New-ServiceNowChangeRequest.ps1 | 16 ++++++++-------- ServiceNow/Public/New-ServiceNowIncident.ps1 | 16 ++++++++-------- ServiceNow/Public/New-ServiceNowQuery.ps1 | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index 5d0f2c1..aaedf93 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -129,14 +129,14 @@ function New-ServiceNowChangeRequest { If ($null -ne $PSBoundParameters.$Parameter) { # Turn the defined parameter name into the ServiceNow attribute name $KeyToAdd = Switch ($Parameter) { - AssignmentGroup { 'assignment_group' } - Caller { 'caller_id' } - Category { 'category' } - Comment { 'comments' } - ConfigurationItem { 'cmdb_ci' } - Description { 'description' } - ShortDescription { 'short_description' } - Subcategory { 'subcategory' } + AssignmentGroup { 'assignment_group'; break} + Caller { 'caller_id'; break} + Category { 'category'; break} + Comment { 'comments'; break} + ConfigurationItem { 'cmdb_ci'; break} + Description { 'description'; break} + ShortDescription { 'short_description'; break} + Subcategory { 'subcategory'; break} } $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) } diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index f3649c5..05efc68 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -119,14 +119,14 @@ function New-ServiceNowIncident{ If ($null -ne $PSBoundParameters.$Parameter) { # Turn the defined parameter name into the ServiceNow attribute name $KeyToAdd = Switch ($Parameter) { - AssignmentGroup {'assignment_group'} - Caller {'caller_id'} - Category {'category'} - Comment {'comments'} - ConfigurationItem {'cmdb_ci'} - Description {'description'} - ShortDescription {'short_description'} - Subcategory {'subcategory'} + AssignmentGroup {'assignment_group'; break} + Caller {'caller_id'; break} + Category {'category'; break} + Comment {'comments'; break} + ConfigurationItem {'cmdb_ci'; break} + Description {'description'; break} + ShortDescription {'short_description'; break} + Subcategory {'subcategory'; break} } $TableEntryValues.Add($KeyToAdd,$PSBoundParameters.$Parameter) } diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index 4e3627e..f572268 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -49,7 +49,7 @@ function New-ServiceNowQuery { # Start the query off with a order direction $Order = Switch ($OrderDirection) { - 'Asc' {'ORDERBY'} + 'Asc' {'ORDERBY'; break} Default {'ORDERBYDESC'} } [void]$Query.Append($Order) From f2f2c28563b50a75831d5cba867b10303b3876fe Mon Sep 17 00:00:00 2001 From: Pepo Date: Tue, 30 Jul 2019 20:57:46 +0200 Subject: [PATCH 167/348] Create Update-ServiceNowRequestItem.ps1 --- .../Public/Update-ServiceNowRequestItem.ps1 | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 ServiceNow/Public/Update-ServiceNowRequestItem.ps1 diff --git a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 new file mode 100644 index 0000000..42cfdbb --- /dev/null +++ b/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 @@ -0,0 +1,49 @@ +function Update-ServiceNowRequestItem { + Param + ( # sys_id of the caller of the Request Item (use 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 + ) + + $updateServiceNowTableEntrySplat = @{ + SysId = $SysId + Table = 'sc_req_item' + Values = $Values + } + + # Update the splat if the parameters have values + if ($null -ne $PSBoundParameters.Connection) + { + $updateServiceNowTableEntrySplat.Add('Connection',$Connection) + } + elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + { + $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) + $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) + } + + Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat +} + From 2612a808950370efd0998576e8b6cfb06bf074d0 Mon Sep 17 00:00:00 2001 From: Pepo Date: Wed, 31 Jul 2019 15:31:23 +0200 Subject: [PATCH 168/348] Update ServiceNow.psd1 ServiceNow.psd1 updated with Update-ServiceNowRequestItem module --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index e74e05f..b0cf2aa 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -66,7 +66,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowTableEntry') +FunctionsToExport = @('Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') # List of all modules packaged with this module # ModuleList = @() From f5b33a2a2a0d23195dd785a5c7112284e95c9b85 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 24 Sep 2019 13:15:13 -0500 Subject: [PATCH 169/348] Switch formatting for readability --- .../Public/New-ServiceNowChangeRequest.ps1 | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index aaedf93..f81fed4 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -2,60 +2,60 @@ function New-ServiceNowChangeRequest { <# .SYNOPSIS Generates a new ServiceNow change request - + .DESCRIPTION Generates a new ServiceNow change request using predefined or custom fields by invoking the ServiceNow API - + .PARAMETER Caller sys_id of the caller of the change request (user Get-ServiceNowUser to retrieve this) - + .PARAMETER ShortDescription Short description of the change request - + .PARAMETER Description Long description of the change request - + .PARAMETER AssignmentGroup sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) - + .PARAMETER Comment Comment to include in the ticket - + .PARAMETER Category Category of the change request (e.g. 'Network') - + .PARAMETER Subcategory Subcategory of the change request (e.g. 'Network') - + .PARAMETER ConfigurationItem sys_id of the configuration item of the change request - + .PARAMETER CustomFields Custom fields as hashtable - + .PARAMETER ServiceNowCredential Credential used to authenticate to ServiceNow - + .PARAMETER ServiceNowURL The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - + .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - + .PARAMETER PassThru Returns the ticket values after creation - + .LINK https://github.com/Sam-Martin/servicenow-powershell - + .EXAMPLE Generate a basic change request attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. - + New-ServiceNowchange request -Caller UserName -ShortDescription 'New PS change request' -Description 'This change request was created from Powershell' -AssignmentGroup ServiceDesk -Comment 'Inline Comment' -Category Office -Subcategory Outlook -ConfigurationItem UserPC1 - + .EXAMPLE Generate an Change Request by 'splatting' all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow instance), This example uses the caller's sys_id value for identification. - + $newServiceNowChangeRequestSplat = @{ Caller = '55ccf91161924edc979d8e7e5627a47d' ShortDescription = 'New PS Change Request' @@ -72,53 +72,53 @@ function New-ServiceNowChangeRequest { } New-ServiceNowChangeRequest @newServiceNowChangeRequestSplat #> - + [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess)] Param( [parameter(Mandatory = $true)] [string]$Caller, - + [parameter(Mandatory = $true)] [string]$ShortDescription, - + [parameter(Mandatory = $false)] [string]$Description, - + [parameter(Mandatory = $false)] [string]$AssignmentGroup, - + [parameter(Mandatory = $false)] [string]$Comment, - + [parameter(Mandatory = $false)] [string]$Category, - + [parameter(Mandatory = $false)] [string]$Subcategory, - + [parameter(Mandatory = $false)] [string]$ConfigurationItem, - + [parameter(Mandatory = $false)] [hashtable]$CustomFields, - + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] [PSCredential]$ServiceNowCredential, - + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, - + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] [ValidateNotNullOrEmpty()] [Hashtable]$Connection, - + # Switch to allow the results to be passed back [Parameter(Mandatory = $false)] [switch]$PassThru ) - + begin { } process { Try { @@ -129,19 +129,19 @@ function New-ServiceNowChangeRequest { If ($null -ne $PSBoundParameters.$Parameter) { # Turn the defined parameter name into the ServiceNow attribute name $KeyToAdd = Switch ($Parameter) { - AssignmentGroup { 'assignment_group'; break} - Caller { 'caller_id'; break} - Category { 'category'; break} - Comment { 'comments'; break} - ConfigurationItem { 'cmdb_ci'; break} - Description { 'description'; break} - ShortDescription { 'short_description'; break} - Subcategory { 'subcategory'; break} + AssignmentGroup {'assignment_group'; break} + Caller {'caller_id'; break} + Category {'category'; break} + Comment {'comments'; break} + ConfigurationItem {'cmdb_ci'; break} + Description {'description'; break} + ShortDescription {'short_description'; break} + Subcategory {'subcategory'; break} } $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) } } - + # Add CustomFields hash pairs to the Table Entry Values hash table If ($null -ne $PSBoundParameters.CustomFields) { $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { @@ -155,19 +155,19 @@ function New-ServiceNowChangeRequest { } } } - + # Throw an error if duplicate fields were provided If ($null -ne $DuplicateTableEntryValues) { $DuplicateKeyList = $DuplicateTableEntryValues -join "," Throw "Ticket fields may only be used once: $DuplicateKeyList" } - + # Table Entry Splat $newServiceNowTableEntrySplat = @{ Table = 'change_request' Values = $TableEntryValues } - + # Update the splat if the parameters have values If ($null -ne $PSBoundParameters.Connection) { $newServiceNowTableEntrySplat.Add('Connection', $Connection) @@ -176,11 +176,11 @@ function New-ServiceNowChangeRequest { $newServiceNowTableEntrySplat.Add('ServiceNowCredential', $ServiceNowCredential) $newServiceNowTableEntrySplat.Add('ServiceNowURL', $ServiceNowURL) } - + # Create the table entry If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { $Result = New-ServiceNowTableEntry @newServiceNowTableEntrySplat - + # Option to return results If ($PSBoundParameters.ContainsKey('Passthru')) { $Result @@ -192,4 +192,4 @@ function New-ServiceNowChangeRequest { } } end { } -} \ No newline at end of file +} From f29a6d035fe47d093b53015a8d961f48d2c73c5c Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 24 Sep 2019 13:15:34 -0500 Subject: [PATCH 170/348] Update remaining Switch statements with breaks --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 4 ++++ ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 2 ++ ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 | 4 ++++ ServiceNow/Public/Get-ServiceNowTableEntry.ps1 | 2 ++ ServiceNow/Public/Remove-ServiceNowAttachment.ps1 | 2 ++ ServiceNow/Public/Update-ServiceNowNumber.ps1 | 2 ++ 6 files changed, 16 insertions(+) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 44ae261..e569f39 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -100,9 +100,11 @@ Function Add-ServiceNowAttachment { 'SpecifyConnectionFields' { $getServiceNowTableEntry.Add('Credential', $Credential) $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) + break } 'UseConnectionObject' { $getServiceNowTableEntry.Add('Connection', $Connection) + break } Default { If (-not (Test-ServiceNowAuthIsSet)) { @@ -117,11 +119,13 @@ Function Add-ServiceNowAttachment { Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + break } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + break } Default { If ((Test-ServiceNowAuthIsSet)) { diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index e02a5c5..2b13b79 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -106,11 +106,13 @@ Function Get-ServiceNowAttachment { Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + break } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + break } Default { If ((Test-ServiceNowAuthIsSet)) { diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 2a474a2..953737f 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -84,9 +84,11 @@ Function Get-ServiceNowAttachmentDetail { 'SpecifyConnectionFields' { $getServiceNowTableEntry.Add('Credential', $Credential) $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) + break } 'UseConnectionObject' { $getServiceNowTableEntry.Add('Connection', $Connection) + break } Default { If (-not (Test-ServiceNowAuthIsSet)) { @@ -101,11 +103,13 @@ Function Get-ServiceNowAttachmentDetail { Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + break } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + break } Default { If ((Test-ServiceNowAuthIsSet)) { diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index 2d915cb..af85222 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -96,9 +96,11 @@ function Get-ServiceNowTableEntry { 'SpecifyConnectionFields' { $getServiceNowTableSplat.Add('Credential', $Credential) $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) + break } 'UseConnectionObject' { $getServiceNowTableSplat.Add('Connection', $Connection) + break } Default {} } diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index bbba4b0..5e75bff 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -60,11 +60,13 @@ Function Remove-ServiceNowAttachment { Switch ($PSCmdlet.ParameterSetName) { 'SpecifyConnectionFields' { $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + break } 'UseConnectionObject' { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + break } Default { If (Test-ServiceNowAuthIsSet) { diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 index e4d35af..f3bc555 100644 --- a/ServiceNow/Public/Update-ServiceNowNumber.ps1 +++ b/ServiceNow/Public/Update-ServiceNowNumber.ps1 @@ -73,12 +73,14 @@ Function Update-ServiceNowNumber { $getServiceNowTableEntry.Add('ServiceNowCredential',$Credential) $getServiceNowTableEntry.Add('ServiceNowURL',$ServiceNowURL) $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' + break } 'UseConnectionObject' { $getServiceNowTableEntry.Add('Connection',$Connection) $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' + break } Default { If ((Test-ServiceNowAuthIsSet)) { From 41b365cee887dbe238fb94d0dea60235671791f6 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 24 Sep 2019 13:30:42 -0500 Subject: [PATCH 171/348] Version 1.7.1 --- ServiceNow/ServiceNow.psd1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index e74e05f..eb2139b 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.7.0' +ModuleVersion = '1.7.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -128,6 +128,8 @@ PrivateData = @{ + + From b3554dba42019fc91bb96f6ac6f870197d04bbd2 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 24 Sep 2019 16:24:40 -0500 Subject: [PATCH 172/348] 1.8.0 - Formatting on Update-ServiceNowRequestItem & Added Pester Test --- .../Public/Update-ServiceNowRequestItem.ps1 | 81 +++++++++++++------ ServiceNow/ServiceNow.psd1 | 4 +- Tests/ServiceNow.Tests.ps1 | 41 +++++++++- 3 files changed, 100 insertions(+), 26 deletions(-) diff --git a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 index 42cfdbb..e5a464c 100644 --- a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 @@ -1,49 +1,82 @@ function Update-ServiceNowRequestItem { - Param - ( # sys_id of the caller of the Request Item (use Get-ServiceNowUser to retrieve this) - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields', mandatory=$true)] - [parameter(ParameterSetName='UseConnectionObject', mandatory=$true)] - [parameter(ParameterSetName='SetGlobalAuth', mandatory=$true)] + <# + .SYNOPSIS + Update an existing request item (RITM) + + .DESCRIPTION + Update an existing request item (RITM) + + .EXAMPLE + Update-ServiceNowRequestItem -SysId $SysId -Values @{property='value'} + + Updates a ticket number with a value providing no return output. + + .EXAMPLE + Update-ServiceNowRequestItem -SysId $SysId -Values @{property='value'} -PassThru + + Updates a ticket number with a value providing return output. + + .NOTES + + #> + + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + + [OutputType([void],[System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + Param ( + # sys_id of the ticket to update + [Parameter(mandatory=$true)] [string]$SysId, - # Hashtable of values to use as the record's properties - [parameter(mandatory=$true)] + # Hashtable of values to use as the record's properties + [Parameter(mandatory=$true)] [hashtable]$Values, - # Credential used to authenticate to ServiceNow + # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [PSCredential]$ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, + [string]$ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection - ) + [Hashtable]$Connection, + + # Switch to allow the results to be passed back + [Parameter(Mandatory=$false)] + [switch]$PassThru + ) $updateServiceNowTableEntrySplat = @{ - SysId = $SysId - Table = 'sc_req_item' + SysId = $SysId + Table = 'sc_req_item' Values = $Values } - + # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { + If ($null -ne $PSBoundParameters.Connection) { $updateServiceNowTableEntrySplat.Add('Connection',$Connection) } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { + ElseIf ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) } - - Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat -} + If ($PSCmdlet.ShouldProcess("$Table/$SysID",$MyInvocation.MyCommand)) { + # Send REST call + $Result = Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat + + # Option to return results + If ($PSBoundParameters.ContainsKey('Passthru')) { + $Result + } + } +} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index f0dd602..851c07b 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.7.1' +ModuleVersion = '1.8.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' @@ -130,6 +130,8 @@ PrivateData = @{ + + diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index 36fc8e0..67c737e 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -253,6 +253,45 @@ Describe "ServiceNow-Module" { $TestTicket.description | Should -Be 'Updated by Pester test Update-ServiceNowNumber with SpecifyConnectionFields works' } + It "Update-ServiceNowRequestItem No PassThru works" { + # Due to a lack of ServiceNow request (REQ) commands this test only works consistently in a developer instance + $TestTicket = Get-ServiceNowRequestItem -MatchExact @{number='RITM0000001';short_description='Apple iPad 3';state=1} -ErrorAction SilentlyContinue + $TestTicket.number | Should -Be 'RITM0000001' -Because 'This test only works in a ServiceNow developer instance for RITM0000001' + + $Values = @{ + 'description' = 'Updated by Pester test Update-ServiceNowRequestItem No PassThru works' + } + + $CommandOutput = Update-ServiceNowRequestItem -SysId $TestTicket.sys_id -Values $Values + + $TestTicket = Get-ServiceNowRequestItem -MatchExact @{sys_id=$TestTicket.sys_id} + $TestTicket.description | Should -Be 'Updated by Pester test Update-ServiceNowRequestItem No PassThru works' + $CommandOutput | Should -BeNullOrEmpty + } + + It "Update-ServiceNowRequestItem with SpecifyConnectionFields and PassThru works" { + # Due to a lack of ServiceNow request (REQ) commands this test only works consistently in a developer instance + $TestTicket = Get-ServiceNowRequestItem -MatchExact @{number='RITM0000001';short_description='Apple iPad 3';state=1} -ErrorAction SilentlyContinue + $TestTicket.number | Should -Be 'RITM0000001' -Because 'This test only works in a ServiceNow developer instance for RITM0000001' + + $Values = @{ + 'description' = 'Updated by Pester test Update-ServiceNowRequestItem with SpecifyConnectionFields works' + } + + $updateServiceNowRequestItemSplat = @{ + SysID = $TestTicket.sys_id + Values = $Values + Credential = $Credential + ServiceNowURL = $Defaults.ServiceNowURL + PassThru = $true + } + $CommandOutput = Update-ServiceNowRequestItem @updateServiceNowRequestItemSplat + + $TestTicket = Get-ServiceNowRequestItem -MatchExact @{sys_id=$TestTicket.sys_id} + $TestTicket.description | Should -Be 'Updated by Pester test Update-ServiceNowRequestItem with SpecifyConnectionFields works' + $CommandOutput | Should -Not -BeNullOrEmpty + } + # Remove Functions It "Remove-ServiceNowTable works" { $TestTicket = Get-ServiceNowIncident -First 1 @@ -270,6 +309,6 @@ Describe "ServiceNow-Module" { } It "Remove-ServiceNowAuth works" { - Remove-ServiceNowAuth | Should be $true + Remove-ServiceNowAuth | Should -Be $true } } From 2d476d94f3fe1e7bcf612f25fd8e3db313f11296 Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 24 Sep 2019 16:35:37 -0500 Subject: [PATCH 173/348] Update ReadMe --- Readme.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 8be8943..0c81e18 100644 --- a/Readme.md +++ b/Readme.md @@ -92,19 +92,25 @@ The module can use the `Connection` parameter in conjunction with the included ` The `Connection` parameter accepts a hashtable object that requires a username, password, and ServiceNowURL. -## Cmdlets +## Functions +* Add-ServiceNowAttachment +* Get-ServiceNowAttachment +* Get-ServiceNowAttachmentDetail * Get-ServiceNowChangeRequest -* Get-ServiceNowConfigurationIte +* Get-ServiceNowConfigurationItem * Get-ServiceNowIncident * Get-ServiceNowRequest +* Get-ServiceNowRequestItem * Get-ServiceNowTable * Get-ServiceNowTableEntry * Get-ServiceNowUser * Get-ServiceNowUserGroup +* New-ServiceNowChangeRequest * New-ServiceNowIncident * New-ServiceNowQuery * New-ServiceNowTableEntry +* Remove-ServiceNowAttachment * Remove-ServiceNowAuth * Remove-ServiceNowTableEntry * Set-ServiceNowAuth @@ -112,6 +118,7 @@ The `Connection` parameter accepts a hashtable object that requires a username, * Update-ServiceNowChangeRequest * Update-ServiceNowIncident * Update-ServiceNowNumber +* Update-ServiceNowRequestItem * Update-ServiceNowTableEntry ## Tests From 59d06b7650402a9c2af28a7cad12c9180d89ed8a Mon Sep 17 00:00:00 2001 From: Rick-2CA Date: Tue, 24 Sep 2019 16:35:53 -0500 Subject: [PATCH 174/348] Remove whitespace at end of file --- ServiceNow/ServiceNow.psd1 | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 851c07b..dd53ba2 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -99,39 +99,3 @@ PrivateData = @{ # DefaultCommandPrefix = '' } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 33917dae6211cf43ebb06cad775d0e21ff41f6ca Mon Sep 17 00:00:00 2001 From: Alex Greenwood Date: Fri, 4 Sep 2020 10:44:24 +0100 Subject: [PATCH 175/348] fix example splat --- ServiceNow/Public/New-ServiceNowIncident.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 05efc68..c28ccf5 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -19,15 +19,15 @@ function New-ServiceNowIncident{ $IncidentParams = @{Caller = "UserName" ShortDescription = "New PS Incident" Description = "This incident was created from Powershell" - AssignmentGroup "ServiceDesk" - Comment "Inline Comment" - Category "Office" - Subcategory "Outlook" - ConfigurationItem UserPC1 + AssignmentGroup = "ServiceDesk" + Comment = "Inline Comment" + Category = "Office" + Subcategory = "Outlook" + ConfigurationItem = UserPC1 CustomFields = @{u_custom1 = "Custom Field Entry" u_another_custom = "Related Test"} } - New-ServiceNowIncident @Params + New-ServiceNowIncident @IncidentParams #> From 8bc6bfc4c333ce53323e73b91d9e716d3019f34f Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 24 Mar 2021 12:05:30 -0400 Subject: [PATCH 176/348] Create bug_report.md --- .github/ISSUE_TEMPLATE/bug_report.md | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..ee833cb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,36 @@ +--- +name: Bug report +about: Report errors or unexpected behavior +title: '' +labels: '' +assignees: '' + +--- + + + +# Environment + +``` +Operating System: +ServiceNow module version: +PowerShell version: +``` + +# Steps to reproduce + + + +# Expected behavior + + + +# Actual behavior + + + +# Screenshots + + From 51bfa42a60c0939494a3882c173d39b2398656d4 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 24 Mar 2021 12:06:52 -0400 Subject: [PATCH 177/348] Create config.yml --- .github/ISSUE_TEMPLATE/config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3ba13e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false From 1986a0dc9b302323fdc944e8e770db8522455092 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 24 Mar 2021 12:08:39 -0400 Subject: [PATCH 178/348] Create documentation_issue.md --- .github/ISSUE_TEMPLATE/documentation_issue.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/documentation_issue.md diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.md b/.github/ISSUE_TEMPLATE/documentation_issue.md new file mode 100644 index 0000000..301dd48 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation_issue.md @@ -0,0 +1,10 @@ +--- +name: Documentation Issue +about: Report issues in the documentation +title: '' +labels: '' +assignees: '' + +--- + + From fe150d149d514b87fa8b5f87e579bb7e29587b7d Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 24 Mar 2021 12:09:46 -0400 Subject: [PATCH 179/348] Create feature_request.md --- .github/ISSUE_TEMPLATE/feature_request.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..6414503 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,21 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +# Summary of the new feature/enhancement + + + +# Proposed technical implementation details (optional) + + From f58ba2b0f9c0196f0bf779433415d0485594088d Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 25 Mar 2021 10:50:13 -0400 Subject: [PATCH 180/348] update refs to move to org --- Readme.md | 16 +++++++------ .../Public/New-ServiceNowChangeRequest.ps1 | 2 +- ServiceNow/Public/New-ServiceNowIncident.ps1 | 2 +- ServiceNow/ServiceNow.psd1 | 23 +++++++------------ 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/Readme.md b/Readme.md index 0c81e18..66aff34 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![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-75%25-yellow.svg) +[![GitHub release](https://img.shields.io/github/release/Snow-Shell/servicenow-powershell.svg)](https://github.com/Snow-Shell/servicenow-powershell/releases/latest) [![GitHub license](https://img.shields.io/github/license/Snow-Shell/servicenow-powershell.svg)](LICENSE) ![Test Coverage](https://img.shields.io/badge/coverage-75%25-yellow.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. @@ -40,7 +40,7 @@ Requires authorization in your ServiceNow tenant. Due to the custom nature of S ## Usage -Download the [latest release](https://github.com/Sam-Martin/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: +Download the [latest release](https://github.com/Snow-Shell/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: `Import-Module ServiceNow` Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module ServiceNow`. @@ -77,9 +77,9 @@ Update-ServiceNowIncident -SysID $Incident.Sys_ID -Values @{comments='Updated vi ### Example - Creating a Incident with custom table entries ```PowerShell -$IncidentParams = @{Caller = "UserName" - ShortDescription = "New PS Incident" - Description = "This incident was created from Powershell" +$IncidentParams = @{Caller = "UserName" + ShortDescription = "New PS Incident" + Description = "This incident was created from Powershell" CustomFields = @{u_service = "MyService" u_incident_type = "Request"} } @@ -129,6 +129,8 @@ This module comes with [Pester](https://github.com/pester/Pester/) tests for uni This module has been created as an abstraction layer to suit my immediate requirements. Contributions are gratefully received however, so please feel free to submit a pull request with additional features or amendments. -## Author +## Authors -Author:: Sam Martin +- [Sam Martin](https://github.com/Sam-Martin) +- [Rick Arroues](https://github.com/Rick-2CA) +- [Greg Brownstein](https://github.com/gdbarron) diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index f81fed4..610c0ca 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -46,7 +46,7 @@ function New-ServiceNowChangeRequest { Returns the ticket values after creation .LINK - https://github.com/Sam-Martin/servicenow-powershell + https://github.com/Snow-Shell/servicenow-powershell .EXAMPLE Generate a basic change request attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 05efc68..fa751a2 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -7,7 +7,7 @@ function New-ServiceNowIncident{ Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API .LINK - https://github.com/Sam-Martin/servicenow-powershell + https://github.com/Snow-Shell/servicenow-powershell .EXAMPLE Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index dd53ba2..24d94f2 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -1,33 +1,26 @@ -# -# Module manifest for module 'ServiceNow' -# -# Generated by: Sam Martin -# -# Generated on: 03/05/2015 -# - + @{ # Script module or binary module file associated with this manifest. RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.8.0' +ModuleVersion = '1.8.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' # Author of this module -Author = 'Sam Martin' +Author = 'Sam Martin', 'Rick Arroues', 'Greg Brownstein' # Company or vendor of this module CompanyName = 'None' # Copyright statement for this module -Copyright = '(c) 2015 Sam. All rights reserved.' +Copyright = '(c) 2015-2021 Snow-Shell. All rights reserved.' # Description of the functionality provided by this module -Description = 'This module provides cmdlets allowing you to retrieve information from your ServiceNow instance`s rest API' +Description = 'This module provides cmdlets allowing you to retrieve information from your ServiceNow instance''s REST API' # Minimum version of the Windows PowerShell engine required by this module # PowerShellVersion = '3.0' @@ -83,17 +76,17 @@ PrivateData = @{ Tags = @('Azure','Automation','ServiceNow','PSModule') # A URL to the license for this module. - LicenseUri = 'https://github.com/Sam-Martin/servicenow-powershell/blob/master/LICENSE' + LicenseUri = 'https://github.com/Snow-Shell/servicenow-powershell/blob/master/LICENSE' # A URL to the main website for this project. - ProjectUri = 'https://github.com/Sam-Martin/servicenow-powershell' + ProjectUri = 'https://github.com/Snow-Shell/servicenow-powershell' } # End of PSData hashtable } # End of PrivateData hashtable # HelpInfo URI of this module -# HelpInfoURI = 'https://github.com/Sam-Martin/servicenow-powershell' +# HelpInfoURI = 'https://github.com/Snow-Shell/servicenow-powershell' # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' From 460e2aa68f8bdd5c6145a1df08b0605c372d1200 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 25 Mar 2021 11:28:20 -0400 Subject: [PATCH 181/348] start changelog --- CHANGELOG.md | 13 +++++++++++++ ServiceNow/ServiceNow.psd1 | 1 + 2 files changed, 14 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f9e8918 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +## v1.8.0 +- Add Update-ServiceNowRequestItem +- Fix switch statements by adding breaks to each condition + +## v1.7.0 +- Add New-ServiceNowChangeRequest + +## v1.6.0 +- Add Update-ServiceNowDateTimeField +- Add Add-ServiceNowAttachment +- Add Get-ServiceNowAttachment +- Add Get-ServiceNowAttachmentDetail +- Add Remove-ServiceNowAttachment \ No newline at end of file diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 24d94f2..55e0a19 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -81,6 +81,7 @@ PrivateData = @{ # A URL to the main website for this project. ProjectUri = 'https://github.com/Snow-Shell/servicenow-powershell' + ReleaseNotes = 'https://github.com/Snow-Shell/servicenow-powershell/blob/master/CHANGELOG.md' } # End of PSData hashtable } # End of PrivateData hashtable From 31da29e879d584f9040d7d75dc0f26f4b987d791 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 25 Mar 2021 11:41:44 -0400 Subject: [PATCH 182/348] update license copyright --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 11069ed..25abcff 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright [yyyy] [name of copyright owner] +Copyright 2015-2021 Snow-Shell Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 0e058759160bc8f0c5d1f4bca3542f228f36ca20 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 25 Mar 2021 11:44:05 -0400 Subject: [PATCH 183/348] update changelog for this version --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9e8918..f7c382f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v1.8.1 +- Update links to reference the new GitHub organization this project will be moved to. Module functionality unchanged. + ## v1.8.0 - Add Update-ServiceNowRequestItem - Fix switch statements by adding breaks to each condition From 950caf4e9c8c98b9eca8c8ecbf44ac8080961c99 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sun, 28 Mar 2021 18:09:11 -0400 Subject: [PATCH 184/348] oauth support, remove global vars, common table get --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 209 ++++++++++++++++++ ServiceNow/Private/Test-ServiceNowURL.ps1 | 18 +- .../Public/Get-ServiceNowChangeRequest.ps1 | 58 ++--- .../Get-ServiceNowConfigurationItem.ps1 | 42 +--- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 60 ++--- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 56 +---- .../Public/Get-ServiceNowRequestItem.ps1 | 56 +---- ServiceNow/Public/Get-ServiceNowTable.ps1 | 130 +++-------- ServiceNow/Public/Get-ServiceNowUser.ps1 | 50 +---- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 50 +---- ServiceNow/Public/New-ServiceNowIncident.ps1 | 163 ++++++-------- ServiceNow/Public/New-ServiceNowSession.ps1 | 84 +++++++ ServiceNow/Public/Remove-ServiceNowAuth.ps1 | 14 +- .../Public/Remove-ServiceNowTableEntry.ps1 | 78 +++---- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 12 +- .../Public/Test-ServiceNowAuthIsSet.ps1 | 4 +- 16 files changed, 511 insertions(+), 573 deletions(-) create mode 100644 ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 create mode 100644 ServiceNow/Public/New-ServiceNowSession.ps1 diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 new file mode 100644 index 0000000..7638f78 --- /dev/null +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -0,0 +1,209 @@ +function Invoke-ServiceNowRestMethod { + <# + .SYNOPSIS + Retrieves records for the specified table + .DESCRIPTION + The Get-ServiceNowTable function retrieves records for the specified table + .INPUTS + None + .OUTPUTS + System.Management.Automation.PSCustomObject + .LINK + Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 +#> + + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(SupportsPaging)] + Param ( + [parameter()] + [ValidateSet('Get', 'Post', 'Patch', 'Delete')] + [string] $Method = 'Get', + + # Name of the table we're querying (e.g. incidents) + [parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$Table, + + [parameter()] + [ValidateNotNullOrEmpty()] + [string] $SysId, + + [parameter()] + [hashtable] $Values, + + # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) + [Parameter()] + [string]$Query, + + # Maximum number of records to return + [Parameter()] + [int]$Limit, + + # Fields to return + [Parameter()] + [Alias('Fields')] + [string[]]$Properties, + + # Whether or not to show human readable display values instead of machine values + [Parameter()] + [ValidateSet('true', 'false', 'all')] + [string]$DisplayValues = 'true', + + [Parameter()] + [PSCredential]$Credential, + + [Parameter()] + [string] $ServiceNowURL, + + [Parameter()] + [hashtable]$Connection, + + [Parameter()] + [hashtable] $ServiceNowSession + ) + + $params = @{ + Method = $Method + ContentType = 'application/json' + } + + # Get credential and ServiceNow REST URL + if ( $ServiceNowSession ) { + $uri = $ServiceNowSession.BaseUri + if ( $ServiceNowSession.AccessToken ) { + $params.Headers = @{ + 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken + } + } + } elseif ( $Credential -and $ServiceNowURL ) { + Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' + $uri = 'https://{0}/api/now/v1' -f $ServiceNowURL + $params.Credential = $Credential + } elseif ( $Connection ) { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $params.Credential = $Credential + $uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri + } else { + throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" + } + + $uri += "/table/$Table" + if ( $SysId ) { + $uri += "/$SysId" + } + $params.Uri = $uri + + if ( $Method -eq 'Get') { + $Body = @{ + 'sysparm_display_value' = $DisplayValues + } + + # Handle paging parameters + # If -Limit was provided, write a warning message, but prioritize it over -First. + # The value of -First defaults to [uint64]::MaxValue if not specified. + # If no paging information was provided, default to the legacy behavior, which was to return 10 records. + + if ($PSBoundParameters.ContainsKey('Limit')) { + Write-Warning "The -Limit parameter is deprecated, and may be removed in a future release. Use the -First parameter instead." + $Body['sysparm_limit'] = $Limit + } elseif ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) { + $Body['sysparm_limit'] = $PSCmdlet.PagingParameters.First + } else { + $Body['sysparm_limit'] = 10 + } + + if ($PSCmdlet.PagingParameters.Skip) { + $Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip + } + + if ($PSCmdlet.PagingParameters.IncludeTotalCount) { + # Accuracy is a double between 0.0 and 1.0 representing an estimated percentage accuracy. + # 0.0 means we have no idea and 1.0 means the number is exact. + + # ServiceNow does return this information in the X-Total-Count response header, + # but we're currently using Invoke-RestMethod to perform the API call, and Invoke-RestMethod + # does not provide the response headers, so we can't capture this info. + + # To properly support this parameter, we'd need to fall back on Invoke-WebRequest, read the + # X-Total-Count header of the response, and update this parameter after performing the API + # call. + + # Reference: + # https://developer.servicenow.com/app.do#!/rest_api_doc?v=jakarta&id=r_TableAPI-GET + + [double] $accuracy = 0.0 + $PSCmdlet.PagingParameters.NewTotalCount($PSCmdlet.PagingParameters.First, $accuracy) + } + + # Populate the query + if ($Query) { + $Body.sysparm_query = $Query + } + + if ($Properties) { + $Body.sysparm_fields = ($Properties -join ',').ToLower() + } + } + + if ( $Values ) { + $Body = $Values | ConvertTo-Json + + #Convert to UTF8 array to support special chars such as the danish "�","�","�" + $body = [System.Text.Encoding]::UTf8.GetBytes($Body) + } + + if ( $Body ) { + $params.Body = $Body + } + + Write-Verbose ($params | Format-List | Out-String) + + $response = Invoke-RestMethod @params + + switch ($Method) { + 'Get' { + $result = $response | Select-Object -ExpandProperty result + $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') + ForEach ($SNResult in $Result) { + ForEach ($Property in $ConvertToDateField) { + If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { + Try { + # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now + $CultureDateTimeFormat = (Get-Culture).DateTimeFormat + $DateFormat = $CultureDateTimeFormat.ShortDatePattern + $TimeFormat = $CultureDateTimeFormat.LongTimePattern + $DateTimeFormat = "$DateFormat $TimeFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } Catch { + Try { + # Universal Format + $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } Catch { + # If the local culture and universal formats both fail keep the property as a string (Do nothing) + $null = 'Silencing a PSSA alert with this line' + } + } + } + } + } + } + + { $_ -in 'Post', 'Patch' } { + $result = $response | Select-Object -ExpandProperty result + } + + 'Delete' { + # nothing to do + } + + Default { + # we should never get here given the list of methods is set + } + } + + $result + # Invoke-RestMethod -Uri $Uri -Credential $Credential -Body $Body -ContentType "application/json" | Select-Object -ExpandProperty Result +} diff --git a/ServiceNow/Private/Test-ServiceNowURL.ps1 b/ServiceNow/Private/Test-ServiceNowURL.ps1 index 55113f8..7924b06 100644 --- a/ServiceNow/Private/Test-ServiceNowURL.ps1 +++ b/ServiceNow/Private/Test-ServiceNowURL.ps1 @@ -9,31 +9,27 @@ Function Test-ServiceNowURL { .EXAMPLE Test-ServiceNowURL -Url tenant.domain.com - This example can have text - .OUTPUTS System.Boolean - #> [OutputType([System.Boolean])] [CmdletBinding()] param ( # Pipeline variable - [Parameter(Mandatory = $true)] + [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNullOrEmpty()] - [string]$Url + [string] $Url ) - begin {} - process { + begin {} + process { Write-Verbose "Testing url: $Url" - if ($Url -match '^\w+\..*\.\w+') { + if ($Url -match '^\w+\..*\.\w+') { $true - } - else { + } else { Throw "The expected URL format is tenant.domain.com" } } - end {} + end {} } diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index eb843c0..d3c5f6c 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowChangeRequest { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -33,61 +33,29 @@ function Get-ServiceNowChangeRequest { [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] + [ValidateScript( { Test-ServiceNowURL -Url $_ })] [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection - ) - - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - MatchExact = $MatchExact - OrderDirection = $OrderDirection - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = 'change_request' - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - } - - # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection', $Connection) - } - elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('Credential', $Credential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - } + [hashtable]$Connection, - # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) - # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } + $result = Get-ServiceNowTable @PSBoundParameters -Table 'change_request' - # Perform query and return each object in the format.ps1xml format - $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ChangeRequest")} + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.ChangeRequest") } } - $Result + $result } diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index e23ac98..bae203c 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -48,46 +48,10 @@ function Get-ServiceNowConfigurationItem { [hashtable]$Connection ) - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - MatchExact = $MatchExact - OrderDirection = $OrderDirection - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = 'cmdb_ci' - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - } - - # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection', $Connection) - } - elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('Credential', $Credential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - } - - # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } - - # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } + $result = Get-ServiceNowTable @PSBoundParameters -Table 'cmdb_ci' - # Perform query and return each object in the format.ps1xml format - $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.ConfigurationItem")} + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.ConfigurationItem") } } - $Result + $result } diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 4aacc83..f5604a7 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -1,6 +1,6 @@ -function Get-ServiceNowIncident{ +function Get-ServiceNowIncident { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -33,61 +33,29 @@ function Get-ServiceNowIncident{ [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] + [ValidateScript( { Test-ServiceNowURL -Url $_ })] [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection - ) - - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - OrderDirection = $OrderDirection - MatchExact = $MatchExact - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = 'incident' - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - } - - # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection', $Connection) - } - elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('Credential', $Credential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - } + [hashtable]$Connection, - # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) - # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } + $result = Get-ServiceNowTable @PSBoundParameters -Table 'incident' - # Perform query and return each object in the format.ps1xml format - $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.Incident")} + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.Incident") } } - $Result + $result } diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index 5357071..bb32b91 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowRequest { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -33,61 +33,29 @@ function Get-ServiceNowRequest { [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateScript({Test-ServiceNowURL -Url $_})] [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection - ) - - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - MatchExact = $MatchExact - OrderDirection = $OrderDirection - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = 'sc_request' - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - } - - # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection', $Connection) - } - elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('Credential', $Credential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - } + [hashtable]$Connection, - # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) - # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } + $result = Get-ServiceNowTable @PSBoundParameters -Table 'sc_request' - # Perform query and return each object in the format.ps1xml format - $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { - $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0, "ServiceNow.Request")} + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.Request") } } - $Result + $result } diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index 1972c13..accc692 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -16,7 +16,7 @@ function Get-ServiceNowRequestItem { #> [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] param( # Machine name of the field to order by [parameter(Mandatory = $false)] @@ -49,60 +49,28 @@ function Get-ServiceNowRequestItem { [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection - ) - - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - MatchExact = $MatchExact - OrderDirection = $OrderDirection - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = 'sc_req_item' - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - } + [hashtable]$Connection, - # Update the Table Splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection', $Connection) - } - elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('Credential', $Credential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - } - - # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) - # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } + $result = Get-ServiceNowTable @PSBoundParameters -Table 'sc_req_item' - # Perform query and return each object in the format.ps1xml format - $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { - $Result | ForEach-Object {$_.PSObject.TypeNames.Insert(0,'ServiceNow.RequestItem')} + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.RequestItem") } } - $Result + $result } diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 9131767..c41fa6e 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -1,5 +1,5 @@ function Get-ServiceNowTable { -<# + <# .SYNOPSIS Retrieves records for the specified table .DESCRIPTION @@ -51,114 +51,42 @@ function Get-ServiceNowTable { [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection + [hashtable]$Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - # Get credential and ServiceNow REST URL - if ($null -ne $Connection) { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' - } - elseif ($null -ne $Credential -and $null -ne $ServiceNowURL) { - Try { - $null = Test-ServiceNowURL -Url $ServiceNowURL -ErrorAction Stop - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' - } - Catch { - Throw $PSItem - } + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + OrderDirection = $OrderDirection + MatchExact = $MatchExact + MatchContains = $MatchContains } - elseif ((Test-ServiceNowAuthIsSet)) { - $Credential = $Global:ServiceNowCredentials - $ServiceNowURL = $global:ServiceNowRESTURL + $Query = New-ServiceNowQuery @newServiceNowQuerySplat + + # Table Splat + $getServiceNowTableSplat = @{ + Table = $Table + Query = $Query + Fields = $Properties + DisplayValues = $DisplayValues + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession } - 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 = @{'sysparm_display_value' = $DisplayValues} - - # Handle paging parameters - # If -Limit was provided, write a warning message, but prioritize it over -First. - # The value of -First defaults to [uint64]::MaxValue if not specified. - # If no paging information was provided, default to the legacy behavior, which was to return 10 records. + # Only add the Limit parameter if it was explicitly provided if ($PSBoundParameters.ContainsKey('Limit')) { - Write-Warning "The -Limit parameter is deprecated, and may be removed in a future release. Use the -First parameter instead." - $Body['sysparm_limit'] = $Limit + $getServiceNowTableSplat.Add('Limit', $Limit) } - elseif ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) { - $Body['sysparm_limit'] = $PSCmdlet.PagingParameters.First - } - else { - $Body['sysparm_limit'] = 10 - } - - if ($PSCmdlet.PagingParameters.Skip) { - $Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip - } - - if ($PSCmdlet.PagingParameters.IncludeTotalCount) { - # Accuracy is a double between 0.0 and 1.0 representing an estimated percentage accuracy. - # 0.0 means we have no idea and 1.0 means the number is exact. - - # ServiceNow does return this information in the X-Total-Count response header, - # but we're currently using Invoke-RestMethod to perform the API call, and Invoke-RestMethod - # does not provide the response headers, so we can't capture this info. - - # To properly support this parameter, we'd need to fall back on Invoke-WebRequest, read the - # X-Total-Count header of the response, and update this parameter after performing the API - # call. - - # Reference: - # https://developer.servicenow.com/app.do#!/rest_api_doc?v=jakarta&id=r_TableAPI-GET - - [double] $accuracy = 0.0 - $PSCmdlet.PagingParameters.NewTotalCount($PSCmdlet.PagingParameters.First, $accuracy) - } - - # Populate the query - if ($Query) { - $Body.sysparm_query = $Query - } - - if ($Properties) { - $Body.sysparm_fields = ($Properties -join ',').ToLower() - } - - # Perform table query and capture results - $Uri = $ServiceNowURL + "/table/$Table" - $Result = (Invoke-RestMethod -Uri $Uri -Credential $Credential -Body $Body -ContentType "application/json").Result - # Convert specific fields to DateTime format - $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') - ForEach ($SNResult in $Result) { - ForEach ($Property in $ConvertToDateField) { - If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { - Try { - # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now - $CultureDateTimeFormat = (Get-Culture).DateTimeFormat - $DateFormat = $CultureDateTimeFormat.ShortDatePattern - $TimeFormat = $CultureDateTimeFormat.LongTimePattern - $DateTimeFormat = "$DateFormat $TimeFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } - Catch { - Try { - # Universal Format - $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } - Catch { - # If the local culture and universal formats both fail keep the property as a string (Do nothing) - $null = 'Silencing a PSSA alert with this line' - } - } - } - } + # Add all provided paging parameters + ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { + $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) } - # Return the results - $Result + Invoke-ServiceNowRestMethod @getServiceNowTableSplat } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index ab969ec..496c128 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowUser{ [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -45,49 +45,17 @@ function Get-ServiceNowUser{ [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection - ) - - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - OrderDirection = $OrderDirection - MatchExact = $MatchExact - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = 'sys_user' - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - } - - # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection', $Connection) - } - elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('Credential', $Credential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - } + [hashtable]$Connection, - # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) - # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } + $result = Get-ServiceNowTable @PSBoundParameters -Table 'sys_user' - # Perform query and return each object in the format.ps1xml format - $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.UserAndUserGroup")} + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.UserAndUserGroup") } } - $Result + $result } diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index d4bae87..f39b7d0 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowUserGroup{ [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] + [CmdletBinding(DefaultParameterSetName='Session', SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -45,49 +45,17 @@ function Get-ServiceNowUserGroup{ [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection - ) - - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - OrderDirection = $OrderDirection - MatchExact = $MatchExact - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = 'sys_user_group' - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - } - - # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) { - $getServiceNowTableSplat.Add('Connection', $Connection) - } - elseif ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $getServiceNowTableSplat.Add('Credential', $Credential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - } + [hashtable]$Connection, - # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) - # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } + $result = Get-ServiceNowTable @PSBoundParameters -Table 'sys_user_group' - # Perform query and return each object in the format.ps1xml format - $Result = Get-ServiceNowTable @getServiceNowTableSplat If (-not $Properties) { - $Result | ForEach-Object{$_.PSObject.TypeNames.Insert(0,"ServiceNow.UserAndUserGroup")} + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.UserAndUserGroup") } } - $Result + $result } diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index fa751a2..e1b42fa 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -1,134 +1,112 @@ -function New-ServiceNowIncident{ <# .SYNOPSIS - Generates a new ServiceNow Incident +Generates a new ServiceNow Incident .DESCRIPTION - Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API +Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API .LINK - https://github.com/Snow-Shell/servicenow-powershell +https://github.com/Snow-Shell/servicenow-powershell .EXAMPLE - Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. - New-ServiceNowIncident -Caller "UserName" -ShortDescription = "New PS Incident" -Description = "This incident was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 +Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. + New-ServiceNowIncident -Caller "UserName" -ShortDescription = "New PS Incident" -Description = "This incident was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 .EXAMPLE - Generate an Incident by "Splatting" all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow Instance): - - $IncidentParams = @{Caller = "UserName" - ShortDescription = "New PS Incident" - Description = "This incident was created from Powershell" - AssignmentGroup "ServiceDesk" - Comment "Inline Comment" - Category "Office" - Subcategory "Outlook" - ConfigurationItem UserPC1 - CustomFields = @{u_custom1 = "Custom Field Entry" - u_another_custom = "Related Test"} - } - New-ServiceNowIncident @Params +Generate an Incident by "Splatting" all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow Instance): + + $IncidentParams = @{Caller = "UserName" + ShortDescription = "New PS Incident" + Description = "This incident was created from Powershell" + AssignmentGroup "ServiceDesk" + Comment "Inline Comment" + Category "Office" + Subcategory "Outlook" + ConfigurationItem UserPC1 + CustomFields = @{u_custom1 = "Custom Field Entry" + u_another_custom = "Related Test"} + } + New-ServiceNowIncident @Params - #> +#> +function New-ServiceNowIncident { Param( # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) - [parameter(Mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter(Mandatory)] [string]$Caller, # Short description of the incident - [parameter(Mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter(Mandatory)] [string]$ShortDescription, # Long description of the incident - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter()] [string]$Description, # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter()] [string]$AssignmentGroup, # Comment to include in the ticket - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter()] [string]$Comment, # Category of the incident (e.g. 'Network') - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter()] [string]$Category, # Subcategory of the incident (e.g. 'Network') - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter()] [string]$Subcategory, # sys_id of the configuration item of the incident - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter()] [string]$ConfigurationItem, # custom fields as hashtable - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] + [parameter()] [hashtable]$CustomFields, # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [PSCredential]$ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential]$Credential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [ValidateNotNullOrEmpty()] + [Hashtable]$Connection, + + [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) # Create a hash table of any defined parameters (not CustomFields) that have values - $DefinedIncidentParameters = @('AssignmentGroup','Caller','Category','Comment','ConfigurationItem','Description','ShortDescription','Subcategory') + $DefinedIncidentParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') $TableEntryValues = @{} ForEach ($Parameter in $DefinedIncidentParameters) { If ($null -ne $PSBoundParameters.$Parameter) { # Turn the defined parameter name into the ServiceNow attribute name $KeyToAdd = Switch ($Parameter) { - AssignmentGroup {'assignment_group'; break} - Caller {'caller_id'; break} - Category {'category'; break} - Comment {'comments'; break} - ConfigurationItem {'cmdb_ci'; break} - Description {'description'; break} - ShortDescription {'short_description'; break} - Subcategory {'subcategory'; break} + AssignmentGroup { 'assignment_group'; break } + Caller { 'caller_id'; break } + Category { 'category'; break } + Comment { 'comments'; break } + ConfigurationItem { 'cmdb_ci'; break } + Description { 'description'; break } + ShortDescription { 'short_description'; break } + Subcategory { 'subcategory'; break } } - $TableEntryValues.Add($KeyToAdd,$PSBoundParameters.$Parameter) + $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) } } @@ -137,9 +115,8 @@ function New-ServiceNowIncident{ $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { If (($TableEntryValues.ContainsKey($Key) -eq $False)) { # Add the unique entry to the table entry values hash table - $TableEntryValues.Add($Key,$CustomFields[$Key]) - } - Else { + $TableEntryValues.Add($Key, $CustomFields[$Key]) + } Else { # Capture the duplicate key name $Key } @@ -153,22 +130,28 @@ function New-ServiceNowIncident{ } # Table Entry Splat - $newServiceNowTableEntrySplat = @{ - Table = 'incident' - Values = $TableEntryValues + $params = @{ + Method = 'Post' + Table = 'incident' + Values = $TableEntryValues + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession } # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { - $newServiceNowTableEntrySplat.Add('Connection',$Connection) - } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { - $newServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) - $newServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) - } - - # Create the table entry - New-ServiceNowTableEntry @newServiceNowTableEntrySplat + # if ($null -ne $PSBoundParameters.Connection) + # { + # $newServiceNowTableEntrySplat.Add('Connection',$Connection) + # } + # elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) + # { + # $newServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) + # $newServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) + # } + + # # Create the table entry + # New-ServiceNowTableEntry @newServiceNowTableEntrySplat + Invoke-ServiceNowRestMethod @params } diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 new file mode 100644 index 0000000..005d692 --- /dev/null +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -0,0 +1,84 @@ +<# +.SYNOPSIS +Create a new ServiceNow session + +.DESCRIPTION + +#> +function New-ServiceNowSession { + + [CmdletBinding(DefaultParameterSetName = 'BasicAuth')] + + param( + [Parameter(Mandatory)] + [ValidateScript( { $_ | Test-ServiceNowURL })] + [Alias('ServiceNowUrl')] + [string] $Url, + + [Parameter(Mandatory, ParameterSetName = 'BasicAuth')] + [Parameter(Mandatory, ParameterSetName = 'OAuth')] + [Alias('Credentials')] + [System.Management.Automation.PSCredential] $Credential, + + [Parameter(Mandatory, ParameterSetName = 'OAuth')] + [System.Management.Automation.PSCredential] $ClientCredential, + + [Parameter(Mandatory, ParameterSetName = 'AccessToken')] + [string] $AccessToken, + + [Parameter()] + [int] $ApiVersion, + + [Parameter()] + [switch] $PassThru + ) + + if ( $ApiVersion -le 0 ) { + $version = '' + } else { + $version = ('/v{0}' -f $ApiVersion) + } + + $newSession = @{ + Domain = $Url + BaseUri = ('https://{0}/api/now{1}' -f $Url, $version) + } + + switch ($PSCmdLet.ParameterSetName) { + 'OAuth' { + $params = @{ + Uri = 'https://{0}/oauth_token.do' -f $Url + Body = @{ + 'grant_type' = 'password' + 'client_id' = $ClientCredential.UserName + 'client_secret' = $ClientCredential.GetNetworkCredential().Password + 'username' = $Credential.UserName + 'password' = $Credential.GetNetworkCredential().Password + } + Method = 'Post' + } + + $token = Invoke-RestMethod @params + $newSession.Add('AccessToken', $token.access_token) + $newSession.Add('RefreshToken', $token.refresh_token) + } + 'AccessToken' { + $newSession.Add('AccessToken', $AccessToken) + } + 'BasicAuth' { + $newSession.Add('Credential', $Credential) + } + 'SSO' { + + } + Default { + + } + } + + if ( $PassThru ) { + $newSession + } else { + $Script:ServiceNowSession = $newSession + } +} diff --git a/ServiceNow/Public/Remove-ServiceNowAuth.ps1 b/ServiceNow/Public/Remove-ServiceNowAuth.ps1 index 35ecbac..c8117a5 100644 --- a/ServiceNow/Public/Remove-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAuth.ps1 @@ -1,18 +1,6 @@ function Remove-ServiceNowAuth{ - If (-not (Test-ServiceNowAuthIsSet)) { - Return $true - } - - Try { - Remove-Variable -Name ServiceNowURL -Scope Global -ErrorAction Stop - Remove-Variable -Name ServiceNowRESTURL -Scope Global -ErrorAction Stop - Remove-Variable -Name ServiceNowCredentials -Scope Global -ErrorAction Stop - } - Catch { - Write-Error $_ - Return $false - } + Write-Warning -Message 'Globally scoped variables have been removed from this module, therefore, Remove-ServiceNowAuth is not needed and will be deprecated' Return $true } diff --git a/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 index 573bbcf..aed3cd1 100644 --- a/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 @@ -1,62 +1,42 @@ -function Remove-ServiceNowTableEntry{ -[CmdletBinding(ConfirmImpact='High')] +function Remove-ServiceNowTableEntry { + [CmdletBinding(DefaultParameterSetName = 'Session', 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')] + [parameter(Mandatory)] [string]$Table, - - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + + # sys_id of the entry we're deleting + [parameter(Mandatory)] + [string] $SysId, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [PSCredential] $ServiceNowCredential, - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + # The URL for the ServiceNow instance being used + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [string] $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection + [Hashtable] $Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - #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' + $params = @{ + Method = 'Delete' + Table = $Table + SysId = $SysId + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession } - 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" - } - - # Fire and return - $Uri = $ServiceNowURL + "/table/$Table/$SysID" - return (Invoke-RestMethod -Uri $uri -Method Delete -Credential $ServiceNowCredential -Body $Body -ContentType "application/json").result + Invoke-ServiceNowRestMethod @params } diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index 7b90983..79f00a3 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -21,17 +21,15 @@ function Set-ServiceNowAuth { [CmdletBinding()] Param ( [Parameter(Mandatory = $true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [ValidateScript({$_ | Test-ServiceNowURL})] [Alias('ServiceNowUrl')] - [string]$Url, + [string] $Url, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [System.Management.Automation.PSCredential] - $Credentials + [System.Management.Automation.PSCredential] $Credentials ) - $Global:serviceNowUrl = 'https://' + $Url - $Global:serviceNowRestUrl = $serviceNowUrl + '/api/now/v1' - $Global:serviceNowCredentials = $Credentials + Write-Warning -Message 'Set-ServiceNowAuth will be deprecated in a future release. Please use New-ServiceNowSession.' + New-ServiceNowSession -Url $Url -Credential $Credentials return $true } diff --git a/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 b/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 index c388819..6627805 100644 --- a/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 +++ b/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 @@ -1,7 +1,7 @@ function Test-ServiceNowAuthIsSet{ - if($Global:ServiceNowCredentials){ + if($script:ServiceNowSession.Credential){ return $true; }else{ return $false; - } + } } From 3d782c74f9ecde5b21abad4448190b37168ff15c Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sun, 28 Mar 2021 18:28:24 -0400 Subject: [PATCH 185/348] export session var --- ServiceNow/Public/New-ServiceNowSession.ps1 | 4 ++++ ServiceNow/Public/Set-ServiceNowAuth.ps1 | 4 ++-- ServiceNow/ServiceNow.psd1 | 7 +++++-- ServiceNow/ServiceNow.psm1 | 7 +++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 005d692..0fbfbae 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -33,6 +33,8 @@ function New-ServiceNowSession { [switch] $PassThru ) + Write-Verbose $PSCmdLet.ParameterSetName + if ( $ApiVersion -le 0 ) { $version = '' } else { @@ -76,6 +78,8 @@ function New-ServiceNowSession { } } + Write-Verbose ($newSession | Out-String) + if ( $PassThru ) { $newSession } else { diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index 79f00a3..5cfc0aa 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -20,12 +20,12 @@ function Set-ServiceNowAuth { #> [CmdletBinding()] Param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory)] [ValidateScript({$_ | Test-ServiceNowURL})] [Alias('ServiceNowUrl')] [string] $Url, - [Parameter(Mandatory = $true)] + [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCredential] $Credentials ) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 55e0a19..bc9f46a 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -59,9 +59,12 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') +FunctionsToExport = @('New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') -# List of all modules packaged with this module + # Variables to export from this module + VariablesToExport = 'ServiceNowSession' + + # List of all modules packaged with this module # ModuleList = @() # List of all files packaged with this module diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index c666d6e..fd144c3 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -14,9 +14,12 @@ foreach($Folder in @('Private', 'Public')) $Files = Get-ChildItem -Path $Root -Filter *.ps1 -Recurse # dot source each file - $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | + $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | ForEach-Object {Write-Verbose $_.basename; . $PSItem.FullName} } } -Export-ModuleMember -Function (Get-ChildItem -Path "$PSScriptRoot\Public\*.ps1").BaseName \ No newline at end of file +Export-ModuleMember -Function (Get-ChildItem -Path "$PSScriptRoot\Public\*.ps1").BaseName + +$Script:ServiceNowSession = @{} +Export-ModuleMember -Variable ServiceNowSession \ No newline at end of file From 225be2c8e237a1ce24911f5226d9152bd79654d5 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sun, 28 Mar 2021 23:04:47 -0400 Subject: [PATCH 186/348] cleanup, function updates for oauth --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 45 +++-- .../Public/Get-ServiceNowAttachment.ps1 | 162 ++++++++++-------- .../Get-ServiceNowConfigurationItem.ps1 | 14 +- .../Public/New-ServiceNowChangeRequest.ps1 | 135 +++++++-------- ServiceNow/Public/New-ServiceNowIncident.ps1 | 37 ++-- .../Public/New-ServiceNowTableEntry.ps1 | 72 ++------ .../Public/Remove-ServiceNowTableEntry.ps1 | 2 +- 7 files changed, 222 insertions(+), 245 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 7638f78..d43cf5a 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -89,7 +89,11 @@ function Invoke-ServiceNowRestMethod { throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" } - $uri += "/table/$Table" + if ( $Table -eq 'attachment' ) { + $uri += '/attachment' + } else { + $uri += "/table/$Table" + } if ( $SysId ) { $uri += "/$SysId" } @@ -164,30 +168,35 @@ function Invoke-ServiceNowRestMethod { switch ($Method) { 'Get' { - $result = $response | Select-Object -ExpandProperty result - $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') - ForEach ($SNResult in $Result) { - ForEach ($Property in $ConvertToDateField) { - If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { - Try { - # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now - $CultureDateTimeFormat = (Get-Culture).DateTimeFormat - $DateFormat = $CultureDateTimeFormat.ShortDatePattern - $TimeFormat = $CultureDateTimeFormat.LongTimePattern - $DateTimeFormat = "$DateFormat $TimeFormat" - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } Catch { + if ( $response.result ) { + + $result = $response | Select-Object -ExpandProperty result + $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') + ForEach ($SNResult in $Result) { + ForEach ($Property in $ConvertToDateField) { + If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { Try { - # Universal Format - $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' + # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now + $CultureDateTimeFormat = (Get-Culture).DateTimeFormat + $DateFormat = $CultureDateTimeFormat.ShortDatePattern + $TimeFormat = $CultureDateTimeFormat.LongTimePattern + $DateTimeFormat = "$DateFormat $TimeFormat" $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) } Catch { - # If the local culture and universal formats both fail keep the property as a string (Do nothing) - $null = 'Silencing a PSSA alert with this line' + Try { + # Universal Format + $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } Catch { + # If the local culture and universal formats both fail keep the property as a string (Do nothing) + $null = 'Silencing a PSSA alert with this line' + } } } } } + } else { + $response } } diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 2b13b79..99f232a 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -45,115 +45,135 @@ Function Get-ServiceNowAttachment { #> - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText', '')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars', '')] - [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess = $true)] Param( # Object number - [Parameter( - Mandatory=$true, - ValueFromPipelineByPropertyName = $true - )] + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id')] - [string]$SysID, + [string]$SysId, - [Parameter( - Mandatory=$true, - ValueFromPipelineByPropertyName = $true - )] + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('file_name')] [string]$FileName, # Out path to download files - [parameter(Mandatory=$false)] - [ValidateScript({ - Test-Path $_ - })] + [parameter()] + [ValidateScript( { + Test-Path $_ + })] [string]$Destination = $PWD.Path, # Options impacting downloads - [parameter(Mandatory=$false)] + [parameter()] [switch]$AllowOverwrite, # Options impacting downloads - [parameter(Mandatory=$false)] + [parameter()] [switch]$AppendNameWithSysID, # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] + [ValidateScript( { $_ | Test-ServiceNowURL })] [ValidateNotNullOrEmpty()] [Alias('Url')] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection + [Hashtable]$Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - begin {} - process { - Try { - # Process credential steps based on parameter set name - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - break - } - 'UseConnectionObject' { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - break - } - Default { - If ((Test-ServiceNowAuthIsSet)) { - $Credential = $Global:ServiceNowCredentials - $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' - } - 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" - } + begin {} + process { + # Try { + $params = @{} + + if ( $ServiceNowSession ) { + $params.uri = $ServiceNowSession.BaseUri + if ( $ServiceNowSession.AccessToken ) { + $params.Headers = @{ + 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken } } + } elseif ( $Credential -and $ServiceNowURL ) { + Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' + $params.$uri = 'https://{0}/api/now/v1' -f $ServiceNowURL + $params.Credential = $Credential + } elseif ( $Connection ) { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $params.Credential = $Credential + $params.$uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri + } else { + throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" + } - # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file - $Uri = $ApiUrl + '/' + $SysID + '/file' - - If ($True -eq $PSBoundParameters.ContainsKey('AppendNameWithSysID')) { - $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), - $SysID,[io.path]::GetExtension($FileName) - } - $OutFile = $Null - $OutFile = Join-Path $Destination $FileName + # Process credential steps based on parameter set name + # Switch ($PSCmdlet.ParameterSetName) { + # 'SpecifyConnectionFields' { + # $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + # break + # } + # 'UseConnectionObject' { + # $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + # $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + # $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + # break + # } + # Default { + # If ((Test-ServiceNowAuthIsSet)) { + # $Credential = $Global:ServiceNowCredentials + # $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' + # } 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" + # } + # } + # } + + # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file + $params.uri += '/attachment/' + $SysID + '/file' + + If ($AppendNameWithSysID.IsPresent) { + $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), + $SysID, [io.path]::GetExtension($FileName) + } + $OutFile = $Null + $OutFile = Join-Path $Destination $FileName - If ((Test-Path $OutFile) -and -not $PSBoundParameters.ContainsKey('AllowOverwrite')) { - $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile - Throw $ThrowMessage - } + If ((Test-Path $OutFile) -and -not $PSBoundParameters.ContainsKey('AllowOverwrite')) { + $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile + Throw $ThrowMessage + } - $invokeRestMethodSplat = @{ - Uri = $Uri - Credential = $Credential - OutFile = $OutFile - } + $params.OutFile = $OutFile + # $invokeRestMethodSplat = @{ + # Uri = $Uri + # Credential = $Credential + # OutFile = $OutFile + # } - If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { - Invoke-RestMethod @invokeRestMethodSplat - } - } - Catch { - Write-Error $PSItem + If ($PSCmdlet.ShouldProcess("SysId $SysId", "Save attachment to file $OutFile")) { + Invoke-RestMethod @params } + # } + # Catch { + # Write-Error $PSItem + # } } - end {} + end {} } diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index bae203c..f46e6e2 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowConfigurationItem { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by [Parameter(Mandatory = $false)] @@ -33,19 +33,23 @@ function Get-ServiceNowConfigurationItem { [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateScript({Test-ServiceNowURL -Url $_})] [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection + [hashtable]$Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) $result = Get-ServiceNowTable @PSBoundParameters -Table 'cmdb_ci' diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index 610c0ca..1ddcc33 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -75,121 +75,112 @@ function New-ServiceNowChangeRequest { [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess)] Param( - [parameter(Mandatory = $true)] + [parameter(Mandatory)] [string]$Caller, - [parameter(Mandatory = $true)] + [parameter(Mandatory)] [string]$ShortDescription, - [parameter(Mandatory = $false)] + [parameter()] [string]$Description, - [parameter(Mandatory = $false)] + [parameter()] [string]$AssignmentGroup, - [parameter(Mandatory = $false)] + [parameter()] [string]$Comment, - [parameter(Mandatory = $false)] + [parameter()] [string]$Category, - [parameter(Mandatory = $false)] + [parameter()] [string]$Subcategory, - [parameter(Mandatory = $false)] + [parameter()] [string]$ConfigurationItem, - [parameter(Mandatory = $false)] + [parameter()] [hashtable]$CustomFields, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [PSCredential]$ServiceNowCredential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable]$Connection, + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession, + # Switch to allow the results to be passed back - [Parameter(Mandatory = $false)] + [Parameter()] [switch]$PassThru ) begin { } process { - Try { - # Create a hash table of any defined parameters (not CustomFields) that have values - $DefinedChangeRequestParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') - $TableEntryValues = @{ } - ForEach ($Parameter in $DefinedChangeRequestParameters) { - If ($null -ne $PSBoundParameters.$Parameter) { - # Turn the defined parameter name into the ServiceNow attribute name - $KeyToAdd = Switch ($Parameter) { - AssignmentGroup {'assignment_group'; break} - Caller {'caller_id'; break} - Category {'category'; break} - Comment {'comments'; break} - ConfigurationItem {'cmdb_ci'; break} - Description {'description'; break} - ShortDescription {'short_description'; break} - Subcategory {'subcategory'; break} - } - $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) + # Create a hash table of any defined parameters (not CustomFields) that have values + $DefinedChangeRequestParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') + $TableEntryValues = @{ } + ForEach ($Parameter in $DefinedChangeRequestParameters) { + If ($null -ne $PSBoundParameters.$Parameter) { + # Turn the defined parameter name into the ServiceNow attribute name + $KeyToAdd = Switch ($Parameter) { + AssignmentGroup { 'assignment_group'; break } + Caller { 'caller_id'; break } + Category { 'category'; break } + Comment { 'comments'; break } + ConfigurationItem { 'cmdb_ci'; break } + Description { 'description'; break } + ShortDescription { 'short_description'; break } + Subcategory { 'subcategory'; break } } + $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) } + } - # Add CustomFields hash pairs to the Table Entry Values hash table - If ($null -ne $PSBoundParameters.CustomFields) { - $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { - If (($TableEntryValues.ContainsKey($Key) -eq $False)) { - # Add the unique entry to the table entry values hash table - $TableEntryValues.Add($Key, $CustomFields[$Key]) - } - Else { - # Capture the duplicate key name - $Key - } + # Add CustomFields hash pairs to the Table Entry Values hash table + If ($null -ne $PSBoundParameters.CustomFields) { + $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { + If (($TableEntryValues.ContainsKey($Key) -eq $False)) { + # Add the unique entry to the table entry values hash table + $TableEntryValues.Add($Key, $CustomFields[$Key]) + } Else { + # Capture the duplicate key name + $Key } } + } - # Throw an error if duplicate fields were provided - If ($null -ne $DuplicateTableEntryValues) { - $DuplicateKeyList = $DuplicateTableEntryValues -join "," - Throw "Ticket fields may only be used once: $DuplicateKeyList" - } - - # Table Entry Splat - $newServiceNowTableEntrySplat = @{ - Table = 'change_request' - Values = $TableEntryValues - } - - # Update the splat if the parameters have values - If ($null -ne $PSBoundParameters.Connection) { - $newServiceNowTableEntrySplat.Add('Connection', $Connection) - } - ElseIf ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $newServiceNowTableEntrySplat.Add('ServiceNowCredential', $ServiceNowCredential) - $newServiceNowTableEntrySplat.Add('ServiceNowURL', $ServiceNowURL) - } + # Throw an error if duplicate fields were provided + If ($null -ne $DuplicateTableEntryValues) { + $DuplicateKeyList = $DuplicateTableEntryValues -join "," + Throw "Ticket fields may only be used once: $DuplicateKeyList" + } - # Create the table entry - If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { - $Result = New-ServiceNowTableEntry @newServiceNowTableEntrySplat + # Table Entry Splat + $params = @{ + Method = 'Post' + Table = 'change_request' + Values = $TableEntryValues + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } - # Option to return results - If ($PSBoundParameters.ContainsKey('Passthru')) { - $Result - } + If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { + $result = Invoke-ServiceNowRestMethod @params + If ($PassThru.IsPresent) { + $result } } - Catch { - Write-Error $PSItem - } } end { } } diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index e1b42fa..4ced96f 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -35,55 +35,55 @@ function New-ServiceNowIncident { # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) [parameter(Mandatory)] - [string]$Caller, + [string] $Caller, # Short description of the incident [parameter(Mandatory)] - [string]$ShortDescription, + [string] $ShortDescription, # Long description of the incident [parameter()] - [string]$Description, + [string] $Description, # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) [parameter()] - [string]$AssignmentGroup, + [string] $AssignmentGroup, # Comment to include in the ticket [parameter()] - [string]$Comment, + [string] $Comment, # Category of the incident (e.g. 'Network') [parameter()] - [string]$Category, + [string] $Category, # Subcategory of the incident (e.g. 'Network') [parameter()] - [string]$Subcategory, + [string] $Subcategory, # sys_id of the configuration item of the incident [parameter()] - [string]$ConfigurationItem, + [string] $ConfigurationItem, # custom fields as hashtable [parameter()] - [hashtable]$CustomFields, + [hashtable] $CustomFields, # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, + [string] $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, + [Hashtable] $Connection, [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] @@ -140,18 +140,5 @@ function New-ServiceNowIncident { ServiceNowSession = $ServiceNowSession } - # Update the splat if the parameters have values - # if ($null -ne $PSBoundParameters.Connection) - # { - # $newServiceNowTableEntrySplat.Add('Connection',$Connection) - # } - # elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - # { - # $newServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) - # $newServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) - # } - - # # Create the table entry - # New-ServiceNowTableEntry @newServiceNowTableEntrySplat Invoke-ServiceNowRestMethod @params } diff --git a/ServiceNow/Public/New-ServiceNowTableEntry.ps1 b/ServiceNow/Public/New-ServiceNowTableEntry.ps1 index 1cc721d..17a2197 100644 --- a/ServiceNow/Public/New-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/New-ServiceNowTableEntry.ps1 @@ -2,68 +2,34 @@ function New-ServiceNowTableEntry{ Param ( # Name of the table we're inserting into (e.g. incidents) - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$Table, - + [parameter(Mandatory)] + [string] $Table, + # Hashtable of values to use as the record's properties - [parameter(mandatory=$false)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [hashtable]$Values, - - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [parameter(Mandatory)] + [hashtable] $Values, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [PSCredential] - $ServiceNowCredential, + [PSCredential] $ServiceNowCredential, - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + # The URL for the ServiceNow instance being used + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [string] - $ServiceNowURL, + $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable] - $Connection - ) - + $Connection, - #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) + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) - # Fire and return - $Uri = $ServiceNowURL + "/table/$Table" - return (Invoke-RestMethod -Uri $uri -Method Post -Credential $ServiceNowCredential -Body $utf8Bytes -ContentType "application/json" -UseBasicParsing).result + Invoke-ServiceNowRestMethod @PSBoundParameters -Method 'Post' } diff --git a/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 index aed3cd1..681044c 100644 --- a/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 @@ -3,7 +3,7 @@ function Remove-ServiceNowTableEntry { Param( # Table containing the entry we're deleting [parameter(Mandatory)] - [string]$Table, + [string] $Table, # sys_id of the entry we're deleting [parameter(Mandatory)] From 6ed4ac7fd9d9cbbea5ad53999bb73331c80548dc Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 29 Mar 2021 14:42:26 -0400 Subject: [PATCH 187/348] parameter cleanup, pipeline support, session for updates --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 2 +- .../Public/Get-ServiceNowAttachment.ps1 | 37 +------ ServiceNow/Public/Get-ServiceNowIncident.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowTable.ps1 | 3 +- .../Public/Get-ServiceNowTableEntry.ps1 | 79 ++++----------- .../Public/Update-ServiceNowIncident.ps1 | 79 ++++++++------- .../Public/Update-ServiceNowRequestItem.ps1 | 78 ++++++++------- .../Public/Update-ServiceNowTableEntry.ps1 | 99 ++++++++----------- 8 files changed, 151 insertions(+), 228 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index d43cf5a..58228c3 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -69,7 +69,7 @@ function Invoke-ServiceNowRestMethod { } # Get credential and ServiceNow REST URL - if ( $ServiceNowSession ) { + if ( $ServiceNowSession.Count -gt 0 ) { $uri = $ServiceNowSession.BaseUri if ( $ServiceNowSession.AccessToken ) { $params.Headers = @{ diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 99f232a..226e69a 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -99,7 +99,6 @@ Function Get-ServiceNowAttachment { begin {} process { - # Try { $params = @{} if ( $ServiceNowSession ) { @@ -122,29 +121,8 @@ Function Get-ServiceNowAttachment { throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" } - # Process credential steps based on parameter set name - # Switch ($PSCmdlet.ParameterSetName) { - # 'SpecifyConnectionFields' { - # $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - # break - # } - # 'UseConnectionObject' { - # $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - # $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - # $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - # break - # } - # Default { - # If ((Test-ServiceNowAuthIsSet)) { - # $Credential = $Global:ServiceNowCredentials - # $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' - # } 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" - # } - # } - # } - - # URI format: https://tenant.service-now.com/api/now/v1/attachment/{sys_id}/file + + # URI format: https://tenant.service-now.com/api/now/attachment/{sys_id}/file $params.uri += '/attachment/' + $SysID + '/file' If ($AppendNameWithSysID.IsPresent) { @@ -154,25 +132,16 @@ Function Get-ServiceNowAttachment { $OutFile = $Null $OutFile = Join-Path $Destination $FileName - If ((Test-Path $OutFile) -and -not $PSBoundParameters.ContainsKey('AllowOverwrite')) { + If ((Test-Path $OutFile) -and -not $AllowOverwrite.IsPresent) { $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile Throw $ThrowMessage } $params.OutFile = $OutFile - # $invokeRestMethodSplat = @{ - # Uri = $Uri - # Credential = $Credential - # OutFile = $OutFile - # } If ($PSCmdlet.ShouldProcess("SysId $SysId", "Save attachment to file $OutFile")) { Invoke-RestMethod @params } - # } - # Catch { - # Write-Error $PSItem - # } } end {} diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index f5604a7..7aafb35 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -39,7 +39,7 @@ function Get-ServiceNowIncident { [PSCredential]$Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { Test-ServiceNowURL -Url $_ })] + [ValidateScript( { $_ | Test-ServiceNowURL })] [Alias('Url')] [string]$ServiceNowURL, diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index c41fa6e..3a888a8 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -14,7 +14,7 @@ function Get-ServiceNowTable { #> [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param ( # Name of the table we're querying (e.g. incidents) [parameter(Mandatory = $true)] @@ -88,5 +88,6 @@ function Get-ServiceNowTable { $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) } + Write-Verbose ($getServiceNowTableSplat | Out-String) Invoke-ServiceNowRestMethod @getServiceNowTableSplat } diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index af85222..a1897f3 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -22,103 +22,58 @@ function Get-ServiceNowTableEntry { [CmdletBinding(DefaultParameterSetName, SupportsPaging)] param( # Table containing the entry we're deleting - [parameter(mandatory = $true)] + [parameter(Mandatory)] [string]$Table, # Machine name of the field to order by - [parameter(Mandatory = $false)] + [parameter()] [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [parameter(Mandatory = $false)] + [parameter()] [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(Mandatory = $false)] + [parameter()] [int]$Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(Mandatory = $false)] + [parameter()] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(Mandatory = $false)] + [parameter()] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [parameter(Mandatory = $false)] + [parameter()] [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateScript({Test-ServiceNowURL -Url $_})] [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection + [hashtable]$Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - Try { - # Query Splat - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - MatchExact = $MatchExact - OrderDirection = $OrderDirection - MatchContains = $MatchContains - ErrorAction = 'Stop' - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - - # Table Splat - $getServiceNowTableSplat = @{ - Table = $Table - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - ErrorAction = 'Stop' - } - - # Update the Table Splat if an applicable parameter set name is in use - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $getServiceNowTableSplat.Add('Credential', $Credential) - $getServiceNowTableSplat.Add('ServiceNowURL', $ServiceNowURL) - break - } - 'UseConnectionObject' { - $getServiceNowTableSplat.Add('Connection', $Connection) - break - } - Default {} - } - - # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } - - # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | Foreach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } - - # Perform table query and return each object. No fancy formatting here as this can pull tables with unknown default properties - Get-ServiceNowTable @getServiceNowTableSplat - } - Catch { - Write-Error $PSItem - } + Get-ServiceNowTable @PSBoundParameters -Table $Table } diff --git a/ServiceNow/Public/Update-ServiceNowIncident.ps1 b/ServiceNow/Public/Update-ServiceNowIncident.ps1 index a0bf4ba..373ab11 100644 --- a/ServiceNow/Public/Update-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Update-ServiceNowIncident.ps1 @@ -1,49 +1,60 @@ function Update-ServiceNowIncident { + + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + Param ( # sys_id of the caller of the incident (use 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)] + [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] + [string] $SysId, + + # Hashtable of values to use as the record's properties + [parameter(Mandatory)] + [hashtable] $Values, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [PSCredential]$ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential] $Credential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, + [string] $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection - ) + [Hashtable] $Connection, - $updateServiceNowTableEntrySplat = @{ - SysId = $SysId - Table = 'incident' - Values = $Values - } - - # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { - $updateServiceNowTableEntrySplat.Add('Connection',$Connection) + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) + + begin { + Write-Warning -Message 'PassThru will be implemented in a future release and the response will not be returned by default. Please update your code to handle this.' } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { - $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) - $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) + + process { + $params = @{ + Method = 'Patch' + Table = 'incident' + SysId = $SysId + Values = $Values + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } + + If ($PSCmdlet.ShouldProcess("Incident $SysID", 'Update values')) { + Invoke-ServiceNowRestMethod @params + } + } - - Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat + + end {} } diff --git a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 index e5a464c..e467f90 100644 --- a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 @@ -20,63 +20,67 @@ function Update-ServiceNowRequestItem { #> - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + [OutputType([void], [System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] - [OutputType([void],[System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] Param ( # sys_id of the ticket to update - [Parameter(mandatory=$true)] - [string]$SysId, + [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] + [string] $SysId, - # Hashtable of values to use as the record's properties - [Parameter(mandatory=$true)] - [hashtable]$Values, + # Hashtable of values to use as the record's properties + [Parameter(Mandatory)] + [hashtable] $Values, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, + [string] $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, + [Hashtable] $Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession, # Switch to allow the results to be passed back - [Parameter(Mandatory=$false)] - [switch]$PassThru + [Parameter()] + [switch] $PassThru ) - $updateServiceNowTableEntrySplat = @{ - SysId = $SysId - Table = 'sc_req_item' - Values = $Values - } + begin {} - # Update the splat if the parameters have values - If ($null -ne $PSBoundParameters.Connection) { - $updateServiceNowTableEntrySplat.Add('Connection',$Connection) - } - ElseIf ($null -ne $PSBoundParameters.Credential -and $null -ne $PSBoundParameters.ServiceNowURL) { - $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) - $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) - } + process { - If ($PSCmdlet.ShouldProcess("$Table/$SysID",$MyInvocation.MyCommand)) { - # Send REST call - $Result = Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat + $params = @{ + Method = 'Patch' + Table = 'sc_req_item' + SysId = $SysId + Values = $Values + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } + + If ($PSCmdlet.ShouldProcess("Request Item $SysID", 'Update values')) { + $response = Invoke-ServiceNowRestMethod @params + } - # Option to return results - If ($PSBoundParameters.ContainsKey('Passthru')) { - $Result + if ( $PassThru.IsPresent ) { + $response } } + + end {} } diff --git a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 index 4e823ed..c23179c 100644 --- a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 @@ -1,71 +1,54 @@ -function Update-ServiceNowTableEntry{ -[CmdletBinding(ConfirmImpact='High')] +function Update-ServiceNowTableEntry { + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] Param( - # sys_id of the entry we're updating - [parameter(mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$SysId, - # Table containing the entry we're updating - [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)] + [parameter(Mandatory)] + [string] $Table, + + # sys_id of the entry we're updating + [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] + [string] $SysId, + + # Hashtable of values to use as the record's properties + [parameter()] + [hashtable] $Values, + + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [PSCredential]$ServiceNowCredential, + [Alias('ServiceNowCredential')] + [PSCredential] $Credential, - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$True)] + # The URL for the ServiceNow instance being used + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, + [string] $ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$True)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, + [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 + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - # 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) + begin {} + + process { + $params = @{ + Method = 'Patch' + Table = $Table + SysId = $SysId + Values = $Values + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } - # Fire and return - $Uri = $ServiceNowURL + "/table/$Table/$SysID" - return (Invoke-RestMethod -Uri $uri -Method Patch -Credential $ServiceNowCredential -Body $utf8Bytes -ContentType "application/json").result + Invoke-ServiceNowRestMethod @params + } } From b7d6ef55da6a8bcf6db24f1274a8919aa655583c Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 31 Mar 2021 19:08:52 -0400 Subject: [PATCH 188/348] fix get query params --- .../Public/Get-ServiceNowChangeRequest.ps1 | 2 +- .../Get-ServiceNowConfigurationItem.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 2 +- .../Public/Get-ServiceNowRequestItem.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowTable.ps1 | 25 ++--- .../Public/Get-ServiceNowTableEntry.ps1 | 18 +++- ServiceNow/Public/Get-ServiceNowUser.ps1 | 2 +- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 2 +- .../Public/New-ServiceNowChangeRequest.ps1 | 3 +- ServiceNow/Public/New-ServiceNowIncident.ps1 | 92 ++++++++++--------- .../Public/Update-ServiceNowChangeRequest.ps1 | 77 +++++++++------- .../Public/Update-ServiceNowTableEntry.ps1 | 8 +- 13 files changed, 131 insertions(+), 106 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index d3c5f6c..4cd1c7c 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -52,7 +52,7 @@ function Get-ServiceNowChangeRequest { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $result = Get-ServiceNowTable @PSBoundParameters -Table 'change_request' + $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'change_request' If (-not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.ChangeRequest") } diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index f46e6e2..9b752a0 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -52,7 +52,7 @@ function Get-ServiceNowConfigurationItem { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $result = Get-ServiceNowTable @PSBoundParameters -Table 'cmdb_ci' + $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'cmdb_ci' If (-not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.ConfigurationItem") } diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 7aafb35..f7f0c28 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -52,7 +52,7 @@ function Get-ServiceNowIncident { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $result = Get-ServiceNowTable @PSBoundParameters -Table 'incident' + $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'incident' If (-not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.Incident") } diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index bb32b91..16ac6a2 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -52,7 +52,7 @@ function Get-ServiceNowRequest { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $result = Get-ServiceNowTable @PSBoundParameters -Table 'sc_request' + $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sc_request' If (-not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.Request") } diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index accc692..9162cc3 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -67,7 +67,7 @@ function Get-ServiceNowRequestItem { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $result = Get-ServiceNowTable @PSBoundParameters -Table 'sc_req_item' + $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sc_req_item' If (-not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.RequestItem") } diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 3a888a8..f3a8f91 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -19,30 +19,30 @@ function Get-ServiceNowTable { # Name of the table we're querying (e.g. incidents) [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [string]$Table, + [string] $Table, # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) [Parameter(Mandatory = $false)] - [string]$Query, + [string] $Query, # Maximum number of records to return [Parameter(Mandatory = $false)] - [int]$Limit, + [int] $Limit, # Fields to return [Parameter(Mandatory = $false)] [Alias('Fields')] - [string[]]$Properties, + [string[]] $Properties, # Whether or not to show human readable display values instead of machine values [Parameter(Mandatory = $false)] [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', + [string] $DisplayValues = 'true', [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] [ValidateNotNullOrEmpty()] @@ -58,14 +58,6 @@ function Get-ServiceNowTable { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - OrderDirection = $OrderDirection - MatchExact = $MatchExact - MatchContains = $MatchContains - } - $Query = New-ServiceNowQuery @newServiceNowQuerySplat - # Table Splat $getServiceNowTableSplat = @{ Table = $Table @@ -78,16 +70,15 @@ function Get-ServiceNowTable { ServiceNowSession = $ServiceNowSession } - # Only add the Limit parameter if it was explicitly provided + # # Only add the Limit parameter if it was explicitly provided if ($PSBoundParameters.ContainsKey('Limit')) { $getServiceNowTableSplat.Add('Limit', $Limit) } - # Add all provided paging parameters + # # Add all provided paging parameters ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) } - Write-Verbose ($getServiceNowTableSplat | Out-String) Invoke-ServiceNowRestMethod @getServiceNowTableSplat } diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index a1897f3..e6d6f22 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -62,7 +62,7 @@ function Get-ServiceNowTableEntry { [PSCredential]$Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [ValidateScript( { Test-ServiceNowURL -Url $_ })] [Alias('Url')] [string]$ServiceNowURL, @@ -75,5 +75,19 @@ function Get-ServiceNowTableEntry { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - Get-ServiceNowTable @PSBoundParameters -Table $Table + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + MatchExact = $MatchExact + OrderDirection = $OrderDirection + MatchContains = $MatchContains + } + $query = New-ServiceNowQuery @newServiceNowQuerySplat + + $paramsWithoutQuery = $PSBoundParameters + $paramsWithoutQuery.Remove('OrderBy') | Out-Null + $paramsWithoutQuery.Remove('MatchExact') | Out-Null + $paramsWithoutQuery.Remove('OrderDirection') | Out-Null + $paramsWithoutQuery.Remove('MatchContains') | Out-Null + + Get-ServiceNowTable @paramsWithoutQuery -Query $query } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 496c128..5580553 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -52,7 +52,7 @@ function Get-ServiceNowUser{ [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $result = Get-ServiceNowTable @PSBoundParameters -Table 'sys_user' + $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sys_user' If (-not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.UserAndUserGroup") } diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index f39b7d0..eb9813c 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -52,7 +52,7 @@ function Get-ServiceNowUserGroup{ [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $result = Get-ServiceNowTable @PSBoundParameters -Table 'sys_user_group' + $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sys_user_group' If (-not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.UserAndUserGroup") } diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index 1ddcc33..f6958d6 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -120,10 +120,11 @@ function New-ServiceNowChangeRequest { # Switch to allow the results to be passed back [Parameter()] - [switch]$PassThru + [switch] $PassThru ) begin { } + process { # Create a hash table of any defined parameters (not CustomFields) that have values $DefinedChangeRequestParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 4ced96f..0245e2e 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -90,55 +90,61 @@ function New-ServiceNowIncident { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - # Create a hash table of any defined parameters (not CustomFields) that have values - $DefinedIncidentParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') - $TableEntryValues = @{} - ForEach ($Parameter in $DefinedIncidentParameters) { - If ($null -ne $PSBoundParameters.$Parameter) { - # Turn the defined parameter name into the ServiceNow attribute name - $KeyToAdd = Switch ($Parameter) { - AssignmentGroup { 'assignment_group'; break } - Caller { 'caller_id'; break } - Category { 'category'; break } - Comment { 'comments'; break } - ConfigurationItem { 'cmdb_ci'; break } - Description { 'description'; break } - ShortDescription { 'short_description'; break } - Subcategory { 'subcategory'; break } + begin { + Write-Warning -Message 'PassThru will be implemented in a future release and the response will not be returned by default. Please update your code to handle this.' + } + + process { + # Create a hash table of any defined parameters (not CustomFields) that have values + $DefinedIncidentParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') + $TableEntryValues = @{} + ForEach ($Parameter in $DefinedIncidentParameters) { + If ($null -ne $PSBoundParameters.$Parameter) { + # Turn the defined parameter name into the ServiceNow attribute name + $KeyToAdd = Switch ($Parameter) { + AssignmentGroup { 'assignment_group'; break } + Caller { 'caller_id'; break } + Category { 'category'; break } + Comment { 'comments'; break } + ConfigurationItem { 'cmdb_ci'; break } + Description { 'description'; break } + ShortDescription { 'short_description'; break } + Subcategory { 'subcategory'; break } + } + $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) } - $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) } - } - # Add CustomFields hash pairs to the Table Entry Values hash table - If ($null -ne $PSBoundParameters.CustomFields) { - $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { - If (($TableEntryValues.ContainsKey($Key) -eq $False)) { - # Add the unique entry to the table entry values hash table - $TableEntryValues.Add($Key, $CustomFields[$Key]) - } Else { - # Capture the duplicate key name - $Key + # Add CustomFields hash pairs to the Table Entry Values hash table + If ($null -ne $PSBoundParameters.CustomFields) { + $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { + If (($TableEntryValues.ContainsKey($Key) -eq $False)) { + # Add the unique entry to the table entry values hash table + $TableEntryValues.Add($Key, $CustomFields[$Key]) + } Else { + # Capture the duplicate key name + $Key + } } } - } - # Throw an error if duplicate fields were provided - If ($null -ne $DuplicateTableEntryValues) { - $DuplicateKeyList = $DuplicateTableEntryValues -join "," - Throw "Ticket fields may only be used once: $DuplicateKeyList" - } + # Throw an error if duplicate fields were provided + If ($null -ne $DuplicateTableEntryValues) { + $DuplicateKeyList = $DuplicateTableEntryValues -join "," + Throw "Ticket fields may only be used once: $DuplicateKeyList" + } - # Table Entry Splat - $params = @{ - Method = 'Post' - Table = 'incident' - Values = $TableEntryValues - Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL - ServiceNowSession = $ServiceNowSession - } + # Table Entry Splat + $params = @{ + Method = 'Post' + Table = 'incident' + Values = $TableEntryValues + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } - Invoke-ServiceNowRestMethod @params + Invoke-ServiceNowRestMethod @params + } } diff --git a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 index 8323f3f..56bb9c2 100644 --- a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 @@ -2,52 +2,61 @@ .EXAMPLE Update-ServiceNowChangeRequest -Values @{ 'state' = 3 } -SysId #> -function Update-ServiceNowChangeRequest -{ +function Update-ServiceNowChangeRequest { + + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + Param( # sys_id of the caller of the incident (use Get-ServiceNowUser to retrieve this) - [parameter(Mandatory=$true)] - [parameter(ParameterSetName='SpecifyConnectionFields')] - [parameter(ParameterSetName='UseConnectionObject')] - [parameter(ParameterSetName='SetGlobalAuth')] - [string]$SysId, - - # Hashtable of values to use as the record's properties - [parameter(Mandatory=$true)] + [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] + [string] $SysId, + + # Hashtable of values to use as the record's properties + [parameter(Mandatory)] [hashtable]$Values, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + # Credential used to authenticate to ServiceNow + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [PSCredential]$ServiceNowCredential, + [PSCredential]$ServiceNowCredential, # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, + [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection - ) + [Hashtable]$Connection, - $updateServiceNowTableEntrySplat = @{ - SysId = $SysId - Table = 'change_request' - Values = $Values - } - - # Update the splat if the parameters have values - if ($null -ne $PSBoundParameters.Connection) - { - $updateServiceNowTableEntrySplat.Add('Connection',$Connection) + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) + + begin { + Write-Warning -Message 'PassThru will be implemented in a future release and the response will not be returned by default. Please update your code to handle this.' } - elseif ($null -ne $PSBoundParameters.ServiceNowCredential -and $null -ne $PSBoundParameters.ServiceNowURL) - { - $updateServiceNowTableEntrySplat.Add('ServiceNowCredential',$ServiceNowCredential) - $updateServiceNowTableEntrySplat.Add('ServiceNowURL',$ServiceNowURL) + + process { + $params = @{ + Method = 'Patch' + Table = 'change_request' + SysId = $SysId + Values = $Values + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } + + If ($PSCmdlet.ShouldProcess("Change request $SysID", 'Update values')) { + Invoke-ServiceNowRestMethod @params + } + } - - Update-ServiceNowTableEntry @updateServiceNowTableEntrySplat + + end {} } diff --git a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 index c23179c..c6e2159 100644 --- a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 @@ -35,7 +35,9 @@ function Update-ServiceNowTableEntry { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - begin {} + begin { + Write-Warning -Message 'PassThru will be implemented in a future release and the response will not be returned by default. Please update your code to handle this.' + } process { $params = @{ @@ -49,6 +51,8 @@ function Update-ServiceNowTableEntry { ServiceNowSession = $ServiceNowSession } - Invoke-ServiceNowRestMethod @params + If ($PSCmdlet.ShouldProcess("$Table $SysID", 'Update values')) { + Invoke-ServiceNowRestMethod @params + } } } From 06a567a1b61674a9e034baa7d4ae1e2bba438aff Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Apr 2021 11:20:38 -0400 Subject: [PATCH 189/348] break out auth to support attachments --- ServiceNow/Private/Get-ServiceNowAuth.ps1 | 53 +++++ .../Private/Invoke-ServiceNowRestMethod.ps1 | 105 +++++---- .../Public/Add-ServiceNowAttachment.ps1 | 223 +++++++++++------- .../Public/Get-ServiceNowAttachment.ps1 | 49 ++-- .../Public/Get-ServiceNowAttachmentDetail.ps1 | 146 ++++-------- .../Public/Get-ServiceNowChangeRequest.ps1 | 18 +- .../Get-ServiceNowConfigurationItem.ps1 | 18 +- ServiceNow/Public/Get-ServiceNowIncident.ps1 | 16 +- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 18 +- .../Public/Get-ServiceNowRequestItem.ps1 | 16 +- ServiceNow/Public/Get-ServiceNowTable.ps1 | 16 +- .../Public/Get-ServiceNowTableEntry.ps1 | 5 +- ServiceNow/Public/Get-ServiceNowUser.ps1 | 24 +- ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 24 +- .../Public/New-ServiceNowChangeRequest.ps1 | 15 +- ServiceNow/Public/New-ServiceNowIncident.ps1 | 18 +- ServiceNow/Public/New-ServiceNowQuery.ps1 | 8 +- ServiceNow/Public/New-ServiceNowSession.ps1 | 8 +- .../Public/New-ServiceNowTableEntry.ps1 | 23 +- .../Public/Remove-ServiceNowAttachment.ps1 | 10 +- .../Public/Update-ServiceNowChangeRequest.ps1 | 15 +- .../Public/Update-ServiceNowIncident.ps1 | 15 +- ServiceNow/Public/Update-ServiceNowNumber.ps1 | 120 ++++------ .../Public/Update-ServiceNowRequestItem.ps1 | 7 +- .../Public/Update-ServiceNowTableEntry.ps1 | 15 +- Tests/AddServiceNowAttachment.Tests.ps1 | 2 +- Tests/GetServiceNowAttachment.Tests.ps1 | 2 +- Tests/GetServiceNowAttachmentDetail.Tests.ps1 | 2 +- Tests/RemoveServiceNowAttachment.Tests.ps1 | 2 +- Tests/ServiceNow.Tests.ps1 | 2 +- 30 files changed, 532 insertions(+), 463 deletions(-) create mode 100644 ServiceNow/Private/Get-ServiceNowAuth.ps1 diff --git a/ServiceNow/Private/Get-ServiceNowAuth.ps1 b/ServiceNow/Private/Get-ServiceNowAuth.ps1 new file mode 100644 index 0000000..d1c60fd --- /dev/null +++ b/ServiceNow/Private/Get-ServiceNowAuth.ps1 @@ -0,0 +1,53 @@ +function Get-ServiceNowAuth { + <# + .SYNOPSIS + .DESCRIPTION + .INPUTS + None + .OUTPUTS + Hashtable +#> + + [OutputType([Hashtable])] + [CmdletBinding()] + Param ( + [Parameter()] + [PSCredential] $Credential, + + [Parameter()] + [string] $ServiceNowURL, + + [Parameter()] + [hashtable] $Connection, + + [Parameter()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) + + $hashOut = @{} + + # Get credential and ServiceNow REST URL + if ( $ServiceNowSession.Count -gt 0 ) { + $hashOut.Uri = $ServiceNowSession.BaseUri + if ( $ServiceNowSession.AccessToken ) { + $hashOut.Headers = @{ + 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken + } + } else { + $hashOut.Credential = $ServiceNowSession.Credential + } + } elseif ( $Credential -and $ServiceNowURL ) { + Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' + $hashOut.Uri = 'https://{0}/api/now/v1' -f $ServiceNowURL + $hashOut.Credential = $Credential + } elseif ( $Connection ) { + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $hashOut.Credential = $Credential + $hashOut.Uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri + } else { + throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" + } + + $hashOut +} diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 58228c3..93f22cb 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -21,83 +21,104 @@ function Invoke-ServiceNowRestMethod { [string] $Method = 'Get', # Name of the table we're querying (e.g. incidents) - [parameter(Mandatory)] + [parameter(Mandatory, ParameterSetName = 'Table')] [ValidateNotNullOrEmpty()] - [string]$Table, + [string] $Table, - [parameter()] + [parameter(ParameterSetName = 'Table')] [ValidateNotNullOrEmpty()] [string] $SysId, + [parameter(ParameterSetName = 'Uri')] + [ValidateNotNullOrEmpty()] + [string] $UriLeaf, + + # [parameter()] + # [hashtable] $Header, + [parameter()] [hashtable] $Values, # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) [Parameter()] - [string]$Query, + [string] $Query, # Maximum number of records to return [Parameter()] - [int]$Limit, + [int] $Limit, # Fields to return [Parameter()] [Alias('Fields')] - [string[]]$Properties, + [string[]] $Properties, # Whether or not to show human readable display values instead of machine values [Parameter()] [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', + [string] $DisplayValues = 'true', [Parameter()] - [PSCredential]$Credential, + [PSCredential] $Credential, [Parameter()] - [string] $ServiceNowURL, + [string] $ServiceNowUrl, [Parameter()] - [hashtable]$Connection, + [hashtable] $Connection, [Parameter()] - [hashtable] $ServiceNowSession + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $params = @{ - Method = $Method - ContentType = 'application/json' + $getAuth = @{ + Credential = $Credential + ServiceNowUrl = $ServiceNowUrl + Connection = $Connection + ServiceNowSession = $ServiceNowSession } - - # Get credential and ServiceNow REST URL - if ( $ServiceNowSession.Count -gt 0 ) { - $uri = $ServiceNowSession.BaseUri - if ( $ServiceNowSession.AccessToken ) { - $params.Headers = @{ - 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken - } + $params = Get-ServiceNowAuth @getAuth + + $params.Method = $Method + $params.ContentType = 'application/json' + + # $params = @{ + # Method = $Method + # ContentType = 'application/json' + # } + + # # Get credential and ServiceNow REST URL + # if ( $ServiceNowSession.Count -gt 0 ) { + # $uri = $ServiceNowSession.BaseUri + # if ( $ServiceNowSession.AccessToken ) { + # $params.Headers = @{ + # 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken + # } + # } + # } elseif ( $Credential -and $ServiceNowURL ) { + # Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' + # $uri = 'https://{0}/api/now/v1' -f $ServiceNowURL + # $params.Credential = $Credential + # } elseif ( $Connection ) { + # $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + # $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + # $params.Credential = $Credential + # $uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri + # } else { + # throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" + # } + + # if ( $Header ) { + # $params.Headers += $Header + # } + + if ( $Table ) { + $params.Uri += "/table/$Table" + if ( $SysId ) { + $params.Uri += "/$SysId" } - } elseif ( $Credential -and $ServiceNowURL ) { - Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' - $uri = 'https://{0}/api/now/v1' -f $ServiceNowURL - $params.Credential = $Credential - } elseif ( $Connection ) { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $params.Credential = $Credential - $uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri } else { - throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" - } - - if ( $Table -eq 'attachment' ) { - $uri += '/attachment' - } else { - $uri += "/table/$Table" - } - if ( $SysId ) { - $uri += "/$SysId" + $params.Uri += $UriLeaf } - $params.Uri = $uri if ( $Method -eq 'Get') { $Body = @{ diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index e569f39..782a8db 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -37,46 +37,46 @@ Function Add-ServiceNowAttachment { #> - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText', '')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars', '')] [OutputType([PSCustomObject[]])] - [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess = $true)] Param( # Object number - [Parameter(Mandatory=$true)] + [Parameter(Mandatory)] [string]$Number, # Table containing the entry - [Parameter(Mandatory=$true)] + [Parameter(Mandatory)] [string]$Table, # Filter results by file name - [parameter(Mandatory=$true)] - [ValidateScript({ - Test-Path $_ - })] + [parameter(Mandatory)] + [ValidateScript( { + Test-Path $_ + })] [string[]]$File, # Content (MIME) type - if not automatically determined - [Parameter(Mandatory=$false)] + [Parameter()] [string]$ContentType, # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] + [ValidateScript( { $_ | Test-ServiceNowURL })] [ValidateNotNullOrEmpty()] [Alias('Url')] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable]$Connection, @@ -85,89 +85,136 @@ Function Add-ServiceNowAttachment { [switch]$PassThru ) - begin {} - process { - Try { - # Use the number and table to determine the sys_id - $getServiceNowTableEntry = @{ - Table = $Table - MatchExact = @{number = $number} - ErrorAction = 'Stop' - } + begin {} + process { + + $getSysIdParams = @{ + Table = $Table + Query = (New-ServiceNowQuery -MatchExact @{'number' = $number }) + Properties = 'sys_id' + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } - # Update the Table Splat if an applicable parameter set name is in use - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $getServiceNowTableEntry.Add('Credential', $Credential) - $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) - break - } - 'UseConnectionObject' { - $getServiceNowTableEntry.Add('Connection', $Connection) - break - } - Default { - If (-not (Test-ServiceNowAuthIsSet)) { - 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" - } - } - } + # Use the number and table to determine the sys_id + $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id - $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + $getAuth = @{ + Credential = $Credential + ServiceNowUrl = $ServiceNowUrl + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + $auth = Get-ServiceNowAuth @getAuth - # Process credential steps based on parameter set name - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - break - } - 'UseConnectionObject' { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - break - } - Default { - If ((Test-ServiceNowAuthIsSet)) { - $Credential = $Global:ServiceNowCredentials - $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' - } - 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" - } - } + ForEach ($Object in $File) { + $FileData = Get-ChildItem $Object -ErrorAction Stop + If (-not $ContentType) { + Add-Type -AssemblyName 'System.Web' + $ContentType = [System.Web.MimeMapping]::GetMimeMapping($FileData.FullName) } - ForEach ($Object in $File) { - $FileData = Get-ChildItem $Object -ErrorAction Stop - If (-not $ContentType) { - Add-Type -AssemblyName 'System.Web' - $ContentType = [System.Web.MimeMapping]::GetMimeMapping($FileData.FullName) - } - - # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot - $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl,$Table,$TableSysID,$FileData.Name - - $invokeRestMethodSplat = @{ - Uri = $Uri - Headers = @{'Content-Type' = $ContentType} - Method = 'POST' - InFile = $FileData.FullName - Credential = $Credential - } + # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot + # $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl, $Table, $TableSysID, $FileData.Name + $invokeRestMethodSplat = $auth + $invokeRestMethodSplat.Uri += '/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $Table, $sysId, $FileData.Name + $invokeRestMethodSplat.Headers += @{'Content-Type' = $ContentType } + $invokeRestMethodSplat += @{ + Method = 'POST' + InFile = $FileData.FullName + } - If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { - $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result + If ($PSCmdlet.ShouldProcess("$Table $Number", 'Add attachment')) { + $invokeRestMethodSplat|ConvertTo-Json + $response = Invoke-RestMethod @invokeRestMethodSplat - If ($PassThru) { - $Result | Update-ServiceNowDateTimeField - } + If ($PassThru) { + $response } } } - Catch { - Write-Error $PSItem - } + + # Try { + # # Use the number and table to determine the sys_id + # $getServiceNowTableEntry = @{ + # Table = $Table + # MatchExact = @{number = $number } + # ErrorAction = 'Stop' + # } + + # # Update the Table Splat if an applicable parameter set name is in use + # Switch ($PSCmdlet.ParameterSetName) { + # 'SpecifyConnectionFields' { + # $getServiceNowTableEntry.Add('Credential', $Credential) + # $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) + # break + # } + # 'UseConnectionObject' { + # $getServiceNowTableEntry.Add('Connection', $Connection) + # break + # } + # Default { + # If (-not (Test-ServiceNowAuthIsSet)) { + # 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" + # } + # } + # } + + # $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id + + # # Process credential steps based on parameter set name + # Switch ($PSCmdlet.ParameterSetName) { + # 'SpecifyConnectionFields' { + # $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + # break + # } + # 'UseConnectionObject' { + # $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + # $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + # $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + # break + # } + # Default { + # If ((Test-ServiceNowAuthIsSet)) { + # $Credential = $Global:ServiceNowCredentials + # $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' + # } 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" + # } + # } + # } + + # ForEach ($Object in $File) { + # $FileData = Get-ChildItem $Object -ErrorAction Stop + # If (-not $ContentType) { + # Add-Type -AssemblyName 'System.Web' + # $ContentType = [System.Web.MimeMapping]::GetMimeMapping($FileData.FullName) + # } + + # # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot + # $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl, $Table, $TableSysID, $FileData.Name + + # $invokeRestMethodSplat = @{ + # Uri = $Uri + # Headers = @{'Content-Type' = $ContentType } + # Method = 'POST' + # InFile = $FileData.FullName + # Credential = $Credential + # } + + # If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { + # $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result + + # If ($PassThru) { + # $Result | Update-ServiceNowDateTimeField + # } + # } + # } + # } Catch { + # Write-Error $PSItem + # } } - end {} + end {} } diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 226e69a..d8968d3 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -45,52 +45,49 @@ Function Get-ServiceNowAttachment { #> - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText', '')] - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars', '')] - [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess = $true)] Param( # Object number [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id')] - [string]$SysId, + [string] $SysId, [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('file_name')] - [string]$FileName, + [string] $FileName, # Out path to download files [parameter()] [ValidateScript( { Test-Path $_ })] - [string]$Destination = $PWD.Path, + [string] $Destination = $PWD.Path, # Options impacting downloads [parameter()] - [switch]$AllowOverwrite, + [switch] $AllowOverwrite, # Options impacting downloads [parameter()] - [switch]$AppendNameWithSysID, + [switch] $AppendNameWithSysID, # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, # The URL for the ServiceNow instance being used [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateScript( { $_ | Test-ServiceNowURL })] [ValidateNotNullOrEmpty()] [Alias('Url')] - [string]$ServiceNowURL, + [string] $ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, + [Hashtable] $Connection, [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] @@ -98,32 +95,18 @@ Function Get-ServiceNowAttachment { ) begin {} + process { - $params = @{} - - if ( $ServiceNowSession ) { - $params.uri = $ServiceNowSession.BaseUri - if ( $ServiceNowSession.AccessToken ) { - $params.Headers = @{ - 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken - } - } - } elseif ( $Credential -and $ServiceNowURL ) { - Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' - $params.$uri = 'https://{0}/api/now/v1' -f $ServiceNowURL - $params.Credential = $Credential - } elseif ( $Connection ) { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $params.Credential = $Credential - $params.$uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri - } else { - throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" + $getAuth = @{ + Credential = $Credential + ServiceNowUrl = $ServiceNowUrl + Connection = $Connection + ServiceNowSession = $ServiceNowSession } - + $params = Get-ServiceNowAuth @getAuth # URI format: https://tenant.service-now.com/api/now/attachment/{sys_id}/file - $params.uri += '/attachment/' + $SysID + '/file' + $params.Uri += '/attachment/' + $SysID + '/file' If ($AppendNameWithSysID.IsPresent) { $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 953737f..17ec696 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -32,121 +32,79 @@ Function Get-ServiceNowAttachmentDetail { #> - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] - [OutputType([System.Management.Automation.PSCustomObject[]])] [CmdletBinding(DefaultParameterSetName)] Param( - # Object number - [Parameter(Mandatory=$true)] - [string]$Number, - # Table containing the entry - [Parameter(Mandatory=$true)] - [string]$Table, + [Parameter(Mandatory)] + [string] $Table, + + # Object number + [Parameter(Mandatory)] + [string] $Number, # Filter results by file name - [parameter(Mandatory=$false)] - [string[]]$FileName, + [parameter()] + [string[]] $FileName, # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] + [ValidateScript( { $_ | Test-ServiceNowURL })] [ValidateNotNullOrEmpty()] [Alias('Url')] - [string]$ServiceNowURL, + [string] $ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [ValidateNotNullOrEmpty()] + [Hashtable] $Connection, + + [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - begin {} - process { - Try { - # Use the number and table to determine the sys_id - $getServiceNowTableEntry = @{ - Table = $Table - MatchExact = @{number = $number} - ErrorAction = 'Stop' - } - - # Update the Table Splat if an applicable parameter set name is in use - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $getServiceNowTableEntry.Add('Credential', $Credential) - $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) - break - } - 'UseConnectionObject' { - $getServiceNowTableEntry.Add('Connection', $Connection) - break - } - Default { - If (-not (Test-ServiceNowAuthIsSet)) { - 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" - } - } - } - - $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id - - # Process credential steps based on parameter set name - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - break - } - 'UseConnectionObject' { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - break - } - Default { - If ((Test-ServiceNowAuthIsSet)) { - $Credential = $Global:ServiceNowCredentials - $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' - } - 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" - } - } - } - - # Populate the query - $Body = @{'sysparm_limit' = 500; 'table_name' = $Table; 'table_sys_id' = $TableSysID} - $Body.sysparm_query = 'ORDERBYfile_name^ORDERBYDESC' - - # Perform table query and capture results - $Uri = $ApiUrl - - $invokeRestMethodSplat = @{ - Uri = $Uri - Body = $Body - Credential = $Credential - ContentType = 'application/json' - } - $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result - - # Filter for requested file names - If ($FileName) { - $Result = $Result | Where-Object {$PSItem.file_name -match ($FileName -join '|')} - } - - $Result | Update-ServiceNowDateTimeField + begin {} + + process { + + $getSysIdParams = @{ + Table = $Table + Query = (New-ServiceNowQuery -MatchExact @{'number' = $number }) + Properties = 'sys_id' + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } + + # Use the number and table to determine the sys_id + $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id + + $getSysIdParams = @{ + Uri = '/attachment' + Query = (New-ServiceNowQuery -MatchExact @{ + table_name = $Table + table_sys_id = $sysId + }) + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession } - Catch { - Write-Error $PSItem + $response = Invoke-ServiceNowRestMethod @getSysIdParams + + if ( $FileName ) { + $response = $response | Where-Object { $_.file_name -in $FileName } } + + $response | Update-ServiceNowDateTimeField } - end {} + end {} } diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 4cd1c7c..6cc44e5 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -3,33 +3,33 @@ function Get-ServiceNowChangeRequest { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by - [Parameter(Mandatory = $false)] + [Parameter()] [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [Parameter(Mandatory = $false)] + [Parameter()] [int]$Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', @@ -39,7 +39,7 @@ function Get-ServiceNowChangeRequest { [PSCredential]$Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { Test-ServiceNowURL -Url $_ })] + [ValidateScript( { $_ | Test-ServiceNowURL })] [Alias('Url')] [string]$ServiceNowURL, @@ -54,7 +54,7 @@ function Get-ServiceNowChangeRequest { $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'change_request' - If (-not $Properties) { + If ( $result -and -not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.ChangeRequest") } } $result diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 9b752a0..46d87b2 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -3,33 +3,33 @@ function Get-ServiceNowConfigurationItem { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by - [Parameter(Mandatory = $false)] + [Parameter()] [string]$OrderBy = 'name', # Direction of ordering (Desc/Asc) - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [Parameter(Mandatory = $false)] + [Parameter()] [int]$Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', @@ -39,7 +39,7 @@ function Get-ServiceNowConfigurationItem { [PSCredential]$Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [ValidateScript({$_ | Test-ServiceNowURL})] [Alias('Url')] [string]$ServiceNowURL, @@ -54,7 +54,7 @@ function Get-ServiceNowConfigurationItem { $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'cmdb_ci' - If (-not $Properties) { + If ( $result -and -not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.ConfigurationItem") } } $result diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index f7f0c28..01a7838 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -3,33 +3,33 @@ function Get-ServiceNowIncident { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by - [Parameter(Mandatory = $false)] + [Parameter()] [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [Parameter(Mandatory = $false)] + [Parameter()] [int]$Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', @@ -54,7 +54,7 @@ function Get-ServiceNowIncident { $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'incident' - If (-not $Properties) { + If ( $result -and -not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.Incident") } } $result diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index 16ac6a2..2b993fc 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -3,33 +3,33 @@ function Get-ServiceNowRequest { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by - [Parameter(Mandatory = $false)] + [Parameter()] [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [Parameter(Mandatory = $false)] + [Parameter()] [int]$Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', @@ -39,7 +39,7 @@ function Get-ServiceNowRequest { [PSCredential]$Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [ValidateScript({$_ | Test-ServiceNowURL})] [Alias('Url')] [string]$ServiceNowURL, @@ -54,7 +54,7 @@ function Get-ServiceNowRequest { $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sc_request' - If (-not $Properties) { + If ( $result -and -not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.Request") } } $result diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 index 9162cc3..7a1b1f6 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 @@ -19,33 +19,33 @@ function Get-ServiceNowRequestItem { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] param( # Machine name of the field to order by - [parameter(Mandatory = $false)] + [parameter()] [string]$OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [parameter(Mandatory = $false)] + [parameter()] [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [parameter(Mandatory = $false)] + [parameter()] [int]$Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(Mandatory = $false)] + [parameter()] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(Mandatory = $false)] + [parameter()] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [parameter(Mandatory = $false)] + [parameter()] [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', @@ -69,7 +69,7 @@ function Get-ServiceNowRequestItem { $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sc_req_item' - If (-not $Properties) { + If ( $result -and -not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.RequestItem") } } $result diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index f3a8f91..236cf91 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -17,39 +17,39 @@ function Get-ServiceNowTable { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param ( # Name of the table we're querying (e.g. incidents) - [parameter(Mandatory = $true)] + [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Table, # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [Parameter(Mandatory = $false)] + [Parameter()] [string] $Query, # Maximum number of records to return - [Parameter(Mandatory = $false)] + [Parameter()] [int] $Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]] $Properties, # Whether or not to show human readable display values instead of machine values - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('true', 'false', 'all')] [string] $DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential] $Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [hashtable]$Connection, diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index e6d6f22..d09afb6 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -62,7 +62,7 @@ function Get-ServiceNowTableEntry { [PSCredential]$Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { Test-ServiceNowURL -Url $_ })] + [ValidateScript( { $_ | Test-ServiceNowURL })] [Alias('Url')] [string]$ServiceNowURL, @@ -89,5 +89,6 @@ function Get-ServiceNowTableEntry { $paramsWithoutQuery.Remove('OrderDirection') | Out-Null $paramsWithoutQuery.Remove('MatchContains') | Out-Null - Get-ServiceNowTable @paramsWithoutQuery -Query $query + Invoke-ServiceNowRestMethod @paramsWithoutQuery -Query $query + # Get-ServiceNowTable @paramsWithoutQuery -Query $query } diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index 5580553..a8bb560 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -3,47 +3,47 @@ function Get-ServiceNowUser{ [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] Param( # Machine name of the field to order by - [Parameter(Mandatory = $false)] + [Parameter()] [string]$OrderBy = 'name', # Direction of ordering (Desc/Asc) - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [Parameter(Mandatory = $false)] + [Parameter()] [int]$Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] + [ValidateScript({$_ | Test-ServiceNowURL})] [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [hashtable]$Connection, @@ -54,7 +54,7 @@ function Get-ServiceNowUser{ $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sys_user' - If (-not $Properties) { + If ( $result -and -not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.UserAndUserGroup") } } $result diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index eb9813c..d5bb3f7 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -3,47 +3,47 @@ function Get-ServiceNowUserGroup{ [CmdletBinding(DefaultParameterSetName='Session', SupportsPaging)] Param( # Machine name of the field to order by - [Parameter(Mandatory = $false)] + [Parameter()] [string]$OrderBy = 'name', # Direction of ordering (Desc/Asc) - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', # Maximum number of records to return - [Parameter(Mandatory = $false)] + [Parameter()] [int]$Limit, # Fields to return - [Parameter(Mandatory = $false)] + [Parameter()] [Alias('Fields')] [string[]]$Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter(Mandatory = $false)] + [Parameter()] [hashtable]$MatchContains = @{}, # Whether or not to show human readable display values instead of machine values - [Parameter(Mandatory = $false)] + [Parameter()] [ValidateSet('true', 'false', 'all')] [string]$DisplayValues = 'true', - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory = $true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] + [ValidateScript({$_ | Test-ServiceNowURL})] [Alias('Url')] [string]$ServiceNowURL, - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory = $true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [hashtable]$Connection, @@ -54,7 +54,7 @@ function Get-ServiceNowUserGroup{ $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sys_user_group' - If (-not $Properties) { + If ( $result -and -not $Properties) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.UserAndUserGroup") } } $result diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index f6958d6..763bea4 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -73,7 +73,8 @@ function New-ServiceNowChangeRequest { New-ServiceNowChangeRequest @newServiceNowChangeRequestSplat #> - [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + Param( [parameter(Mandatory)] [string]$Caller, @@ -118,12 +119,11 @@ function New-ServiceNowChangeRequest { [ValidateNotNullOrEmpty()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, - # Switch to allow the results to be passed back [Parameter()] [switch] $PassThru ) - begin { } + begin {} process { # Create a hash table of any defined parameters (not CustomFields) that have values @@ -176,12 +176,13 @@ function New-ServiceNowChangeRequest { ServiceNowSession = $ServiceNowSession } - If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { - $result = Invoke-ServiceNowRestMethod @params + If ( $PSCmdlet.ShouldProcess($ShortDescription, 'Create new change request') ) { + $response = Invoke-ServiceNowRestMethod @params If ($PassThru.IsPresent) { - $result + $response } } } - end { } + + end {} } diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 0245e2e..7a08328 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -31,6 +31,8 @@ Generate an Incident by "Splatting" all fields used in the 1st example plus some #> function New-ServiceNowIncident { + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + Param( # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) @@ -87,12 +89,13 @@ function New-ServiceNowIncident { [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession + [hashtable] $ServiceNowSession = $script:ServiceNowSession, + + [Parameter()] + [switch] $PassThru ) - begin { - Write-Warning -Message 'PassThru will be implemented in a future release and the response will not be returned by default. Please update your code to handle this.' - } + begin {} process { # Create a hash table of any defined parameters (not CustomFields) that have values @@ -145,6 +148,11 @@ function New-ServiceNowIncident { ServiceNowSession = $ServiceNowSession } - Invoke-ServiceNowRestMethod @params + If ( $PSCmdlet.ShouldProcess($ShortDescription, 'Create new incident') ) { + $response = Invoke-ServiceNowRestMethod @params + If ($PassThru.IsPresent) { + $response + } + } } } diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index f572268..93c2020 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -26,20 +26,20 @@ function New-ServiceNowQuery { param( # Machine name of the field to order by - [parameter(mandatory=$false)] + [parameter()] [string]$OrderBy='opened_at', # Direction of ordering (Desc/Asc) - [parameter(mandatory=$false)] + [parameter()] [ValidateSet("Desc", "Asc")] [string]$OrderDirection='Desc', # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(mandatory=$false)] + [parameter()] [hashtable]$MatchExact, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(mandatory=$false)] + [parameter()] [hashtable]$MatchContains ) diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 0fbfbae..b830556 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -36,7 +36,13 @@ function New-ServiceNowSession { Write-Verbose $PSCmdLet.ParameterSetName if ( $ApiVersion -le 0 ) { - $version = '' + if ( $PSCmdLet.ParameterSetName -eq 'BasicAuth' ) { + # for existing users the expectation is v1 of the api, keep this for now + Write-Warning -Message 'A default of v1 of the API will be deprecated in favor of the latest in a future release.' + $version = '/v1' + } else { + $version = '' + } } else { $version = ('/v{0}' -f $ApiVersion) } diff --git a/ServiceNow/Public/New-ServiceNowTableEntry.ps1 b/ServiceNow/Public/New-ServiceNowTableEntry.ps1 index 17a2197..e5c65ee 100644 --- a/ServiceNow/Public/New-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/New-ServiceNowTableEntry.ps1 @@ -1,4 +1,7 @@ -function New-ServiceNowTableEntry{ +function New-ServiceNowTableEntry { + + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + Param ( # Name of the table we're inserting into (e.g. incidents) @@ -10,26 +13,34 @@ function New-ServiceNowTableEntry{ [hashtable] $Values, # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [PSCredential] $ServiceNowCredential, # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [string] $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection, [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession + [hashtable] $ServiceNowSession = $script:ServiceNowSession, + + [Parameter()] + [switch] $PassThru ) - Invoke-ServiceNowRestMethod @PSBoundParameters -Method 'Post' + If ( $PSCmdlet.ShouldProcess($Table, 'Create new entry') ) { + $response = Invoke-ServiceNowRestMethod @PSBoundParameters -Method 'Post' + If ($PassThru.IsPresent) { + $response + } + } } diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index 5e75bff..aef3464 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -27,27 +27,27 @@ Function Remove-ServiceNowAttachment { Param( # Attachment sys_id [Parameter( - Mandatory=$true, + Mandatory, ValueFromPipelineByPropertyName = $true )] [Alias('sys_id')] [string]$SysID, # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] - [ValidateScript({Test-ServiceNowURL -Url $_})] + [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory)] + [ValidateScript({$_ | Test-ServiceNowURL})] [ValidateNotNullOrEmpty()] [Alias('Url')] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$true)] + [Parameter(ParameterSetName='UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable]$Connection ) diff --git a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 index 56bb9c2..c49813f 100644 --- a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 @@ -33,12 +33,13 @@ function Update-ServiceNowChangeRequest { [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession + [hashtable] $ServiceNowSession = $script:ServiceNowSession, + + [Parameter()] + [switch] $PassThru ) - begin { - Write-Warning -Message 'PassThru will be implemented in a future release and the response will not be returned by default. Please update your code to handle this.' - } + begin {} process { $params = @{ @@ -53,9 +54,11 @@ function Update-ServiceNowChangeRequest { } If ($PSCmdlet.ShouldProcess("Change request $SysID", 'Update values')) { - Invoke-ServiceNowRestMethod @params + $response = Invoke-ServiceNowRestMethod @params + if ( $PassThru.IsPresent ) { + $response + } } - } end {} diff --git a/ServiceNow/Public/Update-ServiceNowIncident.ps1 b/ServiceNow/Public/Update-ServiceNowIncident.ps1 index 373ab11..b936992 100644 --- a/ServiceNow/Public/Update-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Update-ServiceNowIncident.ps1 @@ -30,12 +30,13 @@ function Update-ServiceNowIncident { [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession + [hashtable] $ServiceNowSession = $script:ServiceNowSession, + + [Parameter()] + [switch] $PassThru ) - begin { - Write-Warning -Message 'PassThru will be implemented in a future release and the response will not be returned by default. Please update your code to handle this.' - } + begin {} process { $params = @{ @@ -50,9 +51,11 @@ function Update-ServiceNowIncident { } If ($PSCmdlet.ShouldProcess("Incident $SysID", 'Update values')) { - Invoke-ServiceNowRestMethod @params + $response = Invoke-ServiceNowRestMethod @params + if ( $PassThru.IsPresent ) { + $response + } } - } end {} diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 index f3bc555..d0927df 100644 --- a/ServiceNow/Public/Update-ServiceNowNumber.ps1 +++ b/ServiceNow/Public/Update-ServiceNowNumber.ps1 @@ -19,110 +19,80 @@ Function Update-ServiceNowNumber { #> - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] - [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] Param( + # Table containing the entry + [Parameter(Mandatory)] + [string]$Table, + # Object number - [Parameter(Mandatory=$true)] + [Parameter(Mandatory)] [string]$Number, - # Table containing the entry - [Parameter(Mandatory=$true)] - [string]$Table, + # Hashtable of values to use as the record's properties + [parameter()] + [hashtable]$Values, # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory=$true)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory=$true)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable]$Connection, - # Hashtable of values to use as the record's properties - [parameter(Mandatory=$false)] - [hashtable]$Values, + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession, # Switch to allow the results to be passed back - [parameter(Mandatory=$false)] + [parameter()] [switch]$PassThru ) begin {} - process { - Try { - # Prep a splat to use the provided number to find the sys_id - $getServiceNowTableEntry = @{ - Table = $Table - MatchExact = @{number = $number} - ErrorAction = 'Stop' - } - - # Process credential steps based on parameter set name - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $getServiceNowTableEntry.Add('ServiceNowCredential',$Credential) - $getServiceNowTableEntry.Add('ServiceNowURL',$ServiceNowURL) - $ServiceNowURL = 'https://' + $ServiceNowURL + '/api/now/v1' - break - } - 'UseConnectionObject' { - $getServiceNowTableEntry.Add('Connection',$Connection) - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ServiceNowURL = 'https://' + $Connection.ServiceNowUri + '/api/now/v1' - break - } - Default { - If ((Test-ServiceNowAuthIsSet)) { - $Credential = $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" - } - } - } - - # Use the number and table to determine the sys_id - $SysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id - - # Convert the values to Json and encode them to an UTF8 array to support special chars - $Body = $Values | ConvertTo-Json - $utf8Bytes = [System.Text.Encoding]::Utf8.GetBytes($Body) - - # Setup splat - $Uri = $ServiceNowURL + "/table/$Table/$SysID" - $invokeRestMethodSplat = @{ - Uri = $uri - Method = 'Patch' - Credential = $Credential - Body = $utf8Bytes - ContentType = 'application/json' - } - If ($PSCmdlet.ShouldProcess("$Table/$SysID",$MyInvocation.MyCommand)) { - # Send REST call - $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result + process { + # Prep a splat to use the provided number to find the sys_id + $getSysIdParams = @{ + Table = $Table + Query = (New-ServiceNowQuery -MatchExact @{'number' = $number }) + Properties = 'sys_id' + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession + } - # Option to return results - If ($PSBoundParameters.ContainsKey('Passthru')) { - $Result - } - } + # Use the number and table to determine the sys_id + $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id + + $updateParams = @{ + Method = 'Patch' + Table = $Table + SysId = $sysId + Values = $Values + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession } - Catch { - Write-Error $PSItem + If ($PSCmdlet.ShouldProcess("$Table $SysID", 'Update values')) { + $response = Invoke-ServiceNowRestMethod @updateParams + if ( $PassThru.IsPresent ) { + $response + } } } + end {} } diff --git a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 index e467f90..884dcf3 100644 --- a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 @@ -53,7 +53,6 @@ function Update-ServiceNowRequestItem { [ValidateNotNullOrEmpty()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, - # Switch to allow the results to be passed back [Parameter()] [switch] $PassThru ) @@ -75,11 +74,11 @@ function Update-ServiceNowRequestItem { If ($PSCmdlet.ShouldProcess("Request Item $SysID", 'Update values')) { $response = Invoke-ServiceNowRestMethod @params + if ( $PassThru.IsPresent ) { + $response + } } - if ( $PassThru.IsPresent ) { - $response - } } end {} diff --git a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 index c6e2159..c192273 100644 --- a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 @@ -32,12 +32,13 @@ function Update-ServiceNowTableEntry { [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession + [hashtable] $ServiceNowSession = $script:ServiceNowSession, + + [Parameter()] + [switch] $PassThru ) - begin { - Write-Warning -Message 'PassThru will be implemented in a future release and the response will not be returned by default. Please update your code to handle this.' - } + begin {} process { $params = @{ @@ -52,7 +53,11 @@ function Update-ServiceNowTableEntry { } If ($PSCmdlet.ShouldProcess("$Table $SysID", 'Update values')) { - Invoke-ServiceNowRestMethod @params + $response = Invoke-ServiceNowRestMethod @params + if ( $PassThru.IsPresent ) { + $response + } } + } } diff --git a/Tests/AddServiceNowAttachment.Tests.ps1 b/Tests/AddServiceNowAttachment.Tests.ps1 index 942add3..22ad75e 100644 --- a/Tests/AddServiceNowAttachment.Tests.ps1 +++ b/Tests/AddServiceNowAttachment.Tests.ps1 @@ -1,6 +1,6 @@ [CmdletBinding()] Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory)] [ValidateNotNullorEmpty()] [PSCredential]$Credential ) diff --git a/Tests/GetServiceNowAttachment.Tests.ps1 b/Tests/GetServiceNowAttachment.Tests.ps1 index d62b29a..69c312f 100644 --- a/Tests/GetServiceNowAttachment.Tests.ps1 +++ b/Tests/GetServiceNowAttachment.Tests.ps1 @@ -1,6 +1,6 @@ [CmdletBinding()] Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory)] [ValidateNotNullorEmpty()] [PSCredential]$Credential ) diff --git a/Tests/GetServiceNowAttachmentDetail.Tests.ps1 b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 index 3b67e13..18bd7cd 100644 --- a/Tests/GetServiceNowAttachmentDetail.Tests.ps1 +++ b/Tests/GetServiceNowAttachmentDetail.Tests.ps1 @@ -1,6 +1,6 @@ [CmdletBinding()] Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory)] [ValidateNotNullorEmpty()] [PSCredential]$Credential ) diff --git a/Tests/RemoveServiceNowAttachment.Tests.ps1 b/Tests/RemoveServiceNowAttachment.Tests.ps1 index 9512d76..6563700 100644 --- a/Tests/RemoveServiceNowAttachment.Tests.ps1 +++ b/Tests/RemoveServiceNowAttachment.Tests.ps1 @@ -1,6 +1,6 @@ [CmdletBinding()] Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory)] [ValidateNotNullorEmpty()] [PSCredential]$Credential ) diff --git a/Tests/ServiceNow.Tests.ps1 b/Tests/ServiceNow.Tests.ps1 index 67c737e..d170eba 100644 --- a/Tests/ServiceNow.Tests.ps1 +++ b/Tests/ServiceNow.Tests.ps1 @@ -1,6 +1,6 @@ [CmdletBinding()] Param( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory)] [ValidateNotNullorEmpty()] [PSCredential]$Credential ) From 7411de0a78cae730a6b0bb75d76b703662f5292e Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Apr 2021 11:43:23 -0400 Subject: [PATCH 190/348] allow existing folks to test default api --- .../Public/Add-ServiceNowAttachment.ps1 | 107 +++--------------- ServiceNow/Public/New-ServiceNowSession.ps1 | 8 +- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 4 +- 3 files changed, 18 insertions(+), 101 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 782a8db..fa040b2 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -37,15 +37,12 @@ Function Add-ServiceNowAttachment { #> - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText', '')] - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars', '')] - [OutputType([PSCustomObject[]])] - [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess = $true)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] Param( # Object number [Parameter(Mandatory)] - [string]$Number, + [string] $Number, # Table containing the entry [Parameter(Mandatory)] @@ -56,36 +53,41 @@ Function Add-ServiceNowAttachment { [ValidateScript( { Test-Path $_ })] - [string[]]$File, + [string[]] $File, # Content (MIME) type - if not automatically determined [Parameter()] - [string]$ContentType, + [string] $ContentType, # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, # The URL for the ServiceNow instance being used [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateScript( { $_ | Test-ServiceNowURL })] [ValidateNotNullOrEmpty()] [Alias('Url')] - [string]$ServiceNowURL, + [string] $ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, + [Hashtable] $Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession, # Allow the results to be shown [Parameter()] - [switch]$PassThru + [switch] $PassThru ) begin {} + process { $getSysIdParams = @{ @@ -127,7 +129,7 @@ Function Add-ServiceNowAttachment { } If ($PSCmdlet.ShouldProcess("$Table $Number", 'Add attachment')) { - $invokeRestMethodSplat|ConvertTo-Json + $invokeRestMethodSplat | ConvertTo-Json $response = Invoke-RestMethod @invokeRestMethodSplat If ($PassThru) { @@ -135,86 +137,7 @@ Function Add-ServiceNowAttachment { } } } - - # Try { - # # Use the number and table to determine the sys_id - # $getServiceNowTableEntry = @{ - # Table = $Table - # MatchExact = @{number = $number } - # ErrorAction = 'Stop' - # } - - # # Update the Table Splat if an applicable parameter set name is in use - # Switch ($PSCmdlet.ParameterSetName) { - # 'SpecifyConnectionFields' { - # $getServiceNowTableEntry.Add('Credential', $Credential) - # $getServiceNowTableEntry.Add('ServiceNowURL', $ServiceNowURL) - # break - # } - # 'UseConnectionObject' { - # $getServiceNowTableEntry.Add('Connection', $Connection) - # break - # } - # Default { - # If (-not (Test-ServiceNowAuthIsSet)) { - # 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" - # } - # } - # } - - # $TableSysID = Get-ServiceNowTableEntry @getServiceNowTableEntry | Select-Object -Expand sys_id - - # # Process credential steps based on parameter set name - # Switch ($PSCmdlet.ParameterSetName) { - # 'SpecifyConnectionFields' { - # $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - # break - # } - # 'UseConnectionObject' { - # $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - # $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - # $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - # break - # } - # Default { - # If ((Test-ServiceNowAuthIsSet)) { - # $Credential = $Global:ServiceNowCredentials - # $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' - # } 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" - # } - # } - # } - - # ForEach ($Object in $File) { - # $FileData = Get-ChildItem $Object -ErrorAction Stop - # If (-not $ContentType) { - # Add-Type -AssemblyName 'System.Web' - # $ContentType = [System.Web.MimeMapping]::GetMimeMapping($FileData.FullName) - # } - - # # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot - # $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl, $Table, $TableSysID, $FileData.Name - - # $invokeRestMethodSplat = @{ - # Uri = $Uri - # Headers = @{'Content-Type' = $ContentType } - # Method = 'POST' - # InFile = $FileData.FullName - # Credential = $Credential - # } - - # If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { - # $Result = (Invoke-RestMethod @invokeRestMethodSplat).Result - - # If ($PassThru) { - # $Result | Update-ServiceNowDateTimeField - # } - # } - # } - # } Catch { - # Write-Error $PSItem - # } } + end {} } diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index b830556..0fbfbae 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -36,13 +36,7 @@ function New-ServiceNowSession { Write-Verbose $PSCmdLet.ParameterSetName if ( $ApiVersion -le 0 ) { - if ( $PSCmdLet.ParameterSetName -eq 'BasicAuth' ) { - # for existing users the expectation is v1 of the api, keep this for now - Write-Warning -Message 'A default of v1 of the API will be deprecated in favor of the latest in a future release.' - $version = '/v1' - } else { - $version = '' - } + $version = '' } else { $version = ('/v{0}' -f $ApiVersion) } diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 index 5cfc0aa..4501dc7 100644 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ b/ServiceNow/Public/Set-ServiceNowAuth.ps1 @@ -29,7 +29,7 @@ function Set-ServiceNowAuth { [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCredential] $Credentials ) - Write-Warning -Message 'Set-ServiceNowAuth will be deprecated in a future release. Please use New-ServiceNowSession.' - New-ServiceNowSession -Url $Url -Credential $Credentials + Write-Warning -Message 'Set-ServiceNowAuth will be deprecated in a future release. Please use New-ServiceNowSession. Also, the current default of v1 of the API will be deprecated in favor of the latest in a future release. Set-ServiceNowAuth will utilize v1. To test the latest API, use New-ServiceNowSession.' + New-ServiceNowSession -Url $Url -Credential $Credentials -ApiVersion 1 return $true } From f9a84a1726d5a00d6afeebda327ee82c89bb1d74 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Apr 2021 12:04:30 -0400 Subject: [PATCH 191/348] update attachment functions --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 32 +---- .../Public/Add-ServiceNowAttachment.ps1 | 6 +- .../Public/Remove-ServiceNowAttachment.ps1 | 109 ++++++++++-------- 3 files changed, 64 insertions(+), 83 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 93f22cb..0c0a175 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -81,36 +81,6 @@ function Invoke-ServiceNowRestMethod { $params.Method = $Method $params.ContentType = 'application/json' - # $params = @{ - # Method = $Method - # ContentType = 'application/json' - # } - - # # Get credential and ServiceNow REST URL - # if ( $ServiceNowSession.Count -gt 0 ) { - # $uri = $ServiceNowSession.BaseUri - # if ( $ServiceNowSession.AccessToken ) { - # $params.Headers = @{ - # 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken - # } - # } - # } elseif ( $Credential -and $ServiceNowURL ) { - # Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' - # $uri = 'https://{0}/api/now/v1' -f $ServiceNowURL - # $params.Credential = $Credential - # } elseif ( $Connection ) { - # $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - # $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - # $params.Credential = $Credential - # $uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri - # } else { - # throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" - # } - - # if ( $Header ) { - # $params.Headers += $Header - # } - if ( $Table ) { $params.Uri += "/table/$Table" if ( $SysId ) { @@ -183,7 +153,7 @@ function Invoke-ServiceNowRestMethod { $params.Body = $Body } - Write-Verbose ($params | Format-List | Out-String) + Write-Verbose ($params | ConvertTo-Json) $response = Invoke-RestMethod @params diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index fa040b2..842a7bf 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -121,7 +121,7 @@ Function Add-ServiceNowAttachment { # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot # $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl, $Table, $TableSysID, $FileData.Name $invokeRestMethodSplat = $auth - $invokeRestMethodSplat.Uri += '/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $Table, $sysId, $FileData.Name + $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $Table, $sysId, $FileData.Name $invokeRestMethodSplat.Headers += @{'Content-Type' = $ContentType } $invokeRestMethodSplat += @{ Method = 'POST' @@ -129,11 +129,11 @@ Function Add-ServiceNowAttachment { } If ($PSCmdlet.ShouldProcess("$Table $Number", 'Add attachment')) { - $invokeRestMethodSplat | ConvertTo-Json + Write-Verbose ($invokeRestMethodSplat | ConvertTo-Json) $response = Invoke-RestMethod @invokeRestMethodSplat If ($PassThru) { - $response + $response.result } } } diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index aef3464..1595f62 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -20,77 +20,88 @@ Function Remove-ServiceNowAttachment { #> - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText','')] - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidGlobalVars','')] - - [CmdletBinding(DefaultParameterSetName,SupportsShouldProcess=$true)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess, ConfirmImpact = 'High')] Param( # Attachment sys_id - [Parameter( - Mandatory, - ValueFromPipelineByPropertyName = $true - )] + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id')] [string]$SysID, # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory)] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] [PSCredential]$Credential, # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName='SpecifyConnectionFields', Mandatory)] - [ValidateScript({$_ | Test-ServiceNowURL})] + [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] + [ValidateScript( { $_ | Test-ServiceNowURL })] [ValidateNotNullOrEmpty()] [Alias('Url')] [string]$ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName='UseConnectionObject', Mandatory)] + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [ValidateNotNullOrEmpty()] + [Hashtable]$Connection, + + [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - begin {} - process { - # DELETE: https://tenant.service-now.com/api/now/v1/attachment/{sys_id} - - # Process credential steps based on parameter set name - Switch ($PSCmdlet.ParameterSetName) { - 'SpecifyConnectionFields' { - $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - break - } - 'UseConnectionObject' { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - break - } - Default { - If (Test-ServiceNowAuthIsSet) { - $Credential = $Global:ServiceNowCredentials - $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' - } - 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" - } - } + begin {} + + process { + # DELETE: https://tenant.service-now.com/api/now/v1/attachment/{sys_id} + + # # Process credential steps based on parameter set name + # Switch ($PSCmdlet.ParameterSetName) { + # 'SpecifyConnectionFields' { + # $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' + # break + # } + # 'UseConnectionObject' { + # $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + # $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + # $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' + # break + # } + # Default { + # If (Test-ServiceNowAuthIsSet) { + # $Credential = $Global:ServiceNowCredentials + # $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' + # } 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" + # } + # } + # } + + $params = @{ + Method = 'Delete' + UriLeaf = "/attachment/$SysId" + Connection = $Connection + Credential = $Credential + ServiceNowUrl = $ServiceNowURL + ServiceNowSession = $ServiceNowSession } - $Uri = $ApiUrl + '/' + $SysID - Write-Verbose "URI: $Uri" - - $invokeRestMethodSplat = @{ - Uri = $Uri - Credential = $Credential - Method = 'Delete' + If ($PSCmdlet.ShouldProcess("SysId $SysId", 'Remove attachment')) { + Invoke-ServiceNowRestMethod @params } - If ($PSCmdlet.ShouldProcess($Uri,$MyInvocation.MyCommand)) { - (Invoke-RestMethod @invokeRestMethodSplat).Result - } + # $Uri = $ApiUrl + '/' + $SysID + # Write-Verbose "URI: $Uri" + + # $invokeRestMethodSplat = @{ + # Uri = $Uri + # Credential = $Credential + # Method = 'Delete' + # } + + # If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { + # (Invoke-RestMethod @invokeRestMethodSplat).Result + # } } - end {} + end {} } From 8c76e0d1b6bc82fa7ab089a7e4f6bce818f1109e Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Apr 2021 12:06:50 -0400 Subject: [PATCH 192/348] code cleanup --- .../Public/Remove-ServiceNowAttachment.ps1 | 51 ++++--------------- 1 file changed, 10 insertions(+), 41 deletions(-) diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index 1595f62..1525229 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -16,7 +16,11 @@ Function Remove-ServiceNowAttachment { Removes all attachments from CHG0000001 - .NOTES + .INPUTS + SysId + + .OUTPUTS + None #> @@ -25,25 +29,25 @@ Function Remove-ServiceNowAttachment { # Attachment sys_id [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id')] - [string]$SysID, + [string] $SysId, # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, # The URL for the ServiceNow instance being used [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateScript( { $_ | Test-ServiceNowURL })] [ValidateNotNullOrEmpty()] [Alias('Url')] - [string]$ServiceNowURL, + [string] $ServiceNowURL, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, + [Hashtable] $Connection, [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] @@ -53,29 +57,6 @@ Function Remove-ServiceNowAttachment { begin {} process { - # DELETE: https://tenant.service-now.com/api/now/v1/attachment/{sys_id} - - # # Process credential steps based on parameter set name - # Switch ($PSCmdlet.ParameterSetName) { - # 'SpecifyConnectionFields' { - # $ApiUrl = 'https://' + $ServiceNowURL + '/api/now/v1/attachment' - # break - # } - # 'UseConnectionObject' { - # $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - # $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - # $ApiUrl = 'https://' + $Connection.ServiceNowUri + '/api/now/v1/attachment' - # break - # } - # Default { - # If (Test-ServiceNowAuthIsSet) { - # $Credential = $Global:ServiceNowCredentials - # $ApiUrl = $Global:ServiceNowRESTURL + '/attachment' - # } 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" - # } - # } - # } $params = @{ Method = 'Delete' @@ -89,19 +70,7 @@ Function Remove-ServiceNowAttachment { If ($PSCmdlet.ShouldProcess("SysId $SysId", 'Remove attachment')) { Invoke-ServiceNowRestMethod @params } - - # $Uri = $ApiUrl + '/' + $SysID - # Write-Verbose "URI: $Uri" - - # $invokeRestMethodSplat = @{ - # Uri = $Uri - # Credential = $Credential - # Method = 'Delete' - # } - - # If ($PSCmdlet.ShouldProcess($Uri, $MyInvocation.MyCommand)) { - # (Invoke-RestMethod @invokeRestMethodSplat).Result - # } } + end {} } From bad6aad978c15eb0e10583f85491d3925fc03133 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Apr 2021 12:09:48 -0400 Subject: [PATCH 193/348] code cleanup --- ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 17ec696..4fb175d 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -51,7 +51,7 @@ Function Get-ServiceNowAttachmentDetail { [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, # The URL for the ServiceNow instance being used [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] @@ -87,7 +87,7 @@ Function Get-ServiceNowAttachmentDetail { # Use the number and table to determine the sys_id $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id - $getSysIdParams = @{ + $params = @{ Uri = '/attachment' Query = (New-ServiceNowQuery -MatchExact @{ table_name = $Table @@ -98,7 +98,7 @@ Function Get-ServiceNowAttachmentDetail { ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } - $response = Invoke-ServiceNowRestMethod @getSysIdParams + $response = Invoke-ServiceNowRestMethod @params if ( $FileName ) { $response = $response | Where-Object { $_.file_name -in $FileName } @@ -106,5 +106,6 @@ Function Get-ServiceNowAttachmentDetail { $response | Update-ServiceNowDateTimeField } + end {} } From cbe034c97965c14f42e28b25fe4899cedc5437ae Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Apr 2021 12:20:40 -0400 Subject: [PATCH 194/348] help update --- ServiceNow/Public/New-ServiceNowSession.ps1 | 25 +++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 0fbfbae..0c9496f 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -3,7 +3,28 @@ Create a new ServiceNow session .DESCRIPTION +Create a new ServiceNow session via credentials, OAuth, or access token. +This session will be used by default for all future calls. +Optionally, you can specify the api version you'd like to use; the default is the latest. +.PARAMETER Url +Base domain for your ServiceNow instance, eg. tenant.domain.com + +.PARAMETER Credential +Username and password to connect. This can be used standalone to use basic authentication or in conjunction with ClientCredential for OAuth. + +.PARAMETER ClientCredential +Required for OAuth. Credential where the username is the Client ID and the password is the Secret. + +.PARAMETER AccessToken +Provide the access token directly if obtained outside of this module. + +.PARAMETER ApiVersion +Specific API version to use. The default is the latest. + +.PARAMETER PassThru +Provide the resulting session object to the pipeline as opposed to setting as a script scoped variable to be used by default for other calls. +This is useful if you want to have multiple sessions with different api versions, credentials, etc. #> function New-ServiceNowSession { @@ -42,7 +63,7 @@ function New-ServiceNowSession { } $newSession = @{ - Domain = $Url + Domain = $Url BaseUri = ('https://{0}/api/now{1}' -f $Url, $version) } @@ -78,7 +99,7 @@ function New-ServiceNowSession { } } - Write-Verbose ($newSession | Out-String) + Write-Verbose ($newSession | ConvertTo-Json) if ( $PassThru ) { $newSession From fdb79a1324a1503bfea465782d65b8a6c3df8a4a Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Apr 2021 21:05:10 -0400 Subject: [PATCH 195/348] prep for release, help updates --- CHANGELOG.md | 8 ++++++ Readme.md | 13 ++++++++-- .../Public/Get-ServiceNowChangeRequest.ps1 | 20 +++++++------- ServiceNow/Public/New-ServiceNowSession.ps1 | 26 +++++++++++++++++++ .../Public/Test-ServiceNowAuthIsSet.ps1 | 6 ++--- ServiceNow/ServiceNow.psd1 | 2 +- 6 files changed, 59 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c382f..211dc95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## v2.0 +- Although still in the module for backward compatibility, `Set-ServiceNowAuth` is being replaced with `New-ServiceNowSession`. With this comes OAuth support, removal of global variables, and much more folks have asked for. The ability to provide credentials directly to functions has been retained for this release, but will be deprecated in a future release in favor of using `New-ServiceNowSession`. +- Support for different api versions. `Set-ServiceNowAuth` will continue to use v1 of the api, but `New-ServiceNowSession` defaults to the latest. Check out the `-ApiVersion` parameter of `New-ServiceNowSession`. +- `Remove-ServiceNowAuth` has been retained for this release, but as global variables have been removed, there is no longer a need for it; it will always return `$true`. It will be removed in a future release. +- `-PassThru` added to remaining `Update-` and `New-` functions. Depending on your code, this may be a ***breaking change*** if you expected the result to be returned. +- Pipeline support added to many functions +- Standardizing on coding between all functions + ## v1.8.1 - Update links to reference the new GitHub organization this project will be moved to. Module functionality unchanged. diff --git a/Readme.md b/Readme.md index 66aff34..80137d3 100644 --- a/Readme.md +++ b/Readme.md @@ -6,6 +6,16 @@ This PowerShell module provides a series of cmdlets for interacting with the [Se **IMPORTANT:** Neither this module nor its creator are in any way affiliated with ServiceNow. +## Version 2 + +Building on the great work the community has done thus far, a lot of new updates with this release. +- Although still in the module for backward compatibility, `Set-ServiceNowAuth` is being replaced with `New-ServiceNowSession`. With this comes OAuth support, removal of global variables, and much more folks have asked for. The ability to provide credentials directly to functions has been retained for this release, but will be deprecated in a future release in favor of using `New-ServiceNowSession`. +- Support for different api versions. `Set-ServiceNowAuth` will continue to use v1 of the api, but `New-ServiceNowSession` defaults to the latest. Check out the `-ApiVersion` parameter of `New-ServiceNowSession`. +- `Remove-ServiceNowAuth` has been retained for this release, but as global variables have been removed, there is no longer a need for it; it will always return `$true`. It will be removed in a future release. +- `-PassThru` added to remaining `Update-` and `New-` functions. Depending on your code, this may be a ***breaking change*** if you expected the result to be returned. +- Pipeline support added to many functions +- Standardizing on coding between all functions + ## Version 1 The module has been renamed from PSServiceNow to ServiceNow for version 1. This change moves us away from the reserved "PS" prefix. Since the name change is a major change for the user base and the project was never incremented to v1 we've taken the opportunity to label it such. @@ -108,12 +118,11 @@ The `Connection` parameter accepts a hashtable object that requires a username, * Get-ServiceNowUserGroup * New-ServiceNowChangeRequest * New-ServiceNowIncident +* New-ServiceNowSession * New-ServiceNowQuery * New-ServiceNowTableEntry * Remove-ServiceNowAttachment -* Remove-ServiceNowAuth * Remove-ServiceNowTableEntry -* Set-ServiceNowAuth * Test-ServiceNowAuthIsSet * Update-ServiceNowChangeRequest * Update-ServiceNowIncident diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 6cc44e5..9a441c5 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -4,48 +4,48 @@ function Get-ServiceNowChangeRequest { Param( # Machine name of the field to order by [Parameter()] - [string]$OrderBy = 'opened_at', + [string] $OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) [Parameter()] [ValidateSet('Desc', 'Asc')] - [string]$OrderDirection = 'Desc', + [string] $OrderDirection = 'Desc', # Maximum number of records to return [Parameter()] - [int]$Limit, + [int] $Limit, # Fields to return [Parameter()] [Alias('Fields')] - [string[]]$Properties, + [string[]] $Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [Parameter()] - [hashtable]$MatchExact = @{}, + [hashtable] $MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) [Parameter()] - [hashtable]$MatchContains = @{}, + [hashtable] $MatchContains = @{}, # Whether or not to show human readable display values instead of machine values [Parameter()] [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', + [string] $DisplayValues = 'true', [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateScript( { $_ | Test-ServiceNowURL })] [Alias('Url')] - [string]$ServiceNowURL, + [string] $ServiceNowURL, [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection, + [hashtable] $Connection, [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 0c9496f..92650a5 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -6,6 +6,7 @@ Create a new ServiceNow session Create a new ServiceNow session via credentials, OAuth, or access token. This session will be used by default for all future calls. Optionally, you can specify the api version you'd like to use; the default is the latest. +To use OAuth, ensure you've set it up, https://docs.servicenow.com/bundle/quebec-platform-administration/page/administer/security/task/t_SettingUpOAuth.html. .PARAMETER Url Base domain for your ServiceNow instance, eg. tenant.domain.com @@ -25,6 +26,31 @@ Specific API version to use. The default is the latest. .PARAMETER PassThru Provide the resulting session object to the pipeline as opposed to setting as a script scoped variable to be used by default for other calls. This is useful if you want to have multiple sessions with different api versions, credentials, etc. + +.EXAMPLE +New-ServiceNowSession -Url tenant.domain.com -Credential $mycred +Create a session using basic authentication and save it to a script-scoped variable + +.EXAMPLE +New-ServiceNowSession -Url tenant.domain.com -Credential $mycred -ClientCredential $myClientCred +Create a session using OAuth and save it to a script-scoped variable + +.EXAMPLE +New-ServiceNowSession -Url tenant.domain.com -AccessToken 'asdfasd9f87adsfkksk3nsnd87g6s' +Create a session with an existing access token and save it to a script-scoped variable + +.EXAMPLE +$session = New-ServiceNowSession -Url tenant.domain.com -Credential $mycred -ClientCredential $myClientCred -PassThru +Create a session using OAuth and save it as a local variable to be provided to functions directly + +.INPUTS +None + +.OUTPUTS +Hashtable if -PassThru provided + +.LINK +https://docs.servicenow.com/bundle/quebec-platform-administration/page/administer/security/reference/r_OAuthAPIRequestParameters.html #> function New-ServiceNowSession { diff --git a/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 b/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 index 6627805..dc36c7d 100644 --- a/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 +++ b/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 @@ -1,7 +1,7 @@ function Test-ServiceNowAuthIsSet{ - if($script:ServiceNowSession.Credential){ - return $true; + if ( $ServiceNowSession.Credential -or $ServiceNowSession.AccessToken ){ + return $true }else{ - return $false; + return $false } } diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index bc9f46a..0c8ee65 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '1.8.1' +ModuleVersion = '2.0.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 5df23bba2bcf0263316656996e7f5c8c309a5451 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 13 Apr 2021 15:41:02 -0400 Subject: [PATCH 196/348] proxy support --- CHANGELOG.md | 3 ++ ServiceNow/Private/Get-ServiceNowAuth.ps1 | 12 +++++ ServiceNow/Public/New-ServiceNowSession.ps1 | 54 ++++++++++++++++++--- ServiceNow/ServiceNow.psd1 | 2 +- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 211dc95..e233cee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v2.1 +- Add proxy support, [#97](https://github.com/Snow-Shell/servicenow-powershell/issues/97). Thanks, @mhackethal! + ## v2.0 - Although still in the module for backward compatibility, `Set-ServiceNowAuth` is being replaced with `New-ServiceNowSession`. With this comes OAuth support, removal of global variables, and much more folks have asked for. The ability to provide credentials directly to functions has been retained for this release, but will be deprecated in a future release in favor of using `New-ServiceNowSession`. - Support for different api versions. `Set-ServiceNowAuth` will continue to use v1 of the api, but `New-ServiceNowSession` defaults to the latest. Check out the `-ApiVersion` parameter of `New-ServiceNowSession`. diff --git a/ServiceNow/Private/Get-ServiceNowAuth.ps1 b/ServiceNow/Private/Get-ServiceNowAuth.ps1 index d1c60fd..e714831 100644 --- a/ServiceNow/Private/Get-ServiceNowAuth.ps1 +++ b/ServiceNow/Private/Get-ServiceNowAuth.ps1 @@ -36,15 +36,27 @@ function Get-ServiceNowAuth { } else { $hashOut.Credential = $ServiceNowSession.Credential } + + if ( $ServiceNowSession.Proxy ) { + $hashOut.Proxy = $ServiceNowSession.Proxy + if ( $ServiceNowSession.ProxyCredential ) { + $hashOut.ProxyCredential = $ServiceNowSession.ProxyCredential + } else { + $hashOut.ProxyUseDefaultCredentials = $true + } + } + } elseif ( $Credential -and $ServiceNowURL ) { Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' $hashOut.Uri = 'https://{0}/api/now/v1' -f $ServiceNowURL $hashOut.Credential = $Credential + } elseif ( $Connection ) { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $hashOut.Credential = $Credential $hashOut.Uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri + } else { throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" } diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 92650a5..eb4b8c6 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -20,6 +20,12 @@ Required for OAuth. Credential where the username is the Client ID and the pass .PARAMETER AccessToken Provide the access token directly if obtained outside of this module. +.PARAMETER Proxy +Use a proxy server for the request, rather than connecting directly. Provide the full url. + +.PARAMETER ProxyCredential +Credential of user who can access Proxy. If not provided, the current user will be used. + .PARAMETER ApiVersion Specific API version to use. The default is the latest. @@ -43,6 +49,10 @@ Create a session with an existing access token and save it to a script-scoped va $session = New-ServiceNowSession -Url tenant.domain.com -Credential $mycred -ClientCredential $myClientCred -PassThru Create a session using OAuth and save it as a local variable to be provided to functions directly +.EXAMPLE +New-ServiceNowSession -Url tenant.domain.com -Credential $mycred -Proxy http://1.2.3.4 +Create a session utilizing a proxy to connect + .INPUTS None @@ -64,15 +74,29 @@ function New-ServiceNowSession { [Parameter(Mandatory, ParameterSetName = 'BasicAuth')] [Parameter(Mandatory, ParameterSetName = 'OAuth')] + [Parameter(Mandatory, ParameterSetName = 'BasicAuthProxy')] + [Parameter(Mandatory, ParameterSetName = 'OAuthProxy')] [Alias('Credentials')] [System.Management.Automation.PSCredential] $Credential, [Parameter(Mandatory, ParameterSetName = 'OAuth')] + [Parameter(Mandatory, ParameterSetName = 'OAuthProxy')] [System.Management.Automation.PSCredential] $ClientCredential, [Parameter(Mandatory, ParameterSetName = 'AccessToken')] + [Parameter(Mandatory, ParameterSetName = 'AccessTokenProxy')] [string] $AccessToken, + [Parameter(Mandatory, ParameterSetName = 'BasicAuthProxy')] + [Parameter(Mandatory, ParameterSetName = 'OAuthProxy')] + [Parameter(Mandatory, ParameterSetName = 'AccessTokenProxy')] + [string] $Proxy, + + [Parameter(ParameterSetName = 'BasicAuthProxy')] + [Parameter(ParameterSetName = 'OAuthProxy')] + [Parameter(ParameterSetName = 'AccessTokenProxy')] + [System.Management.Automation.PSCredential] $ProxyCredential, + [Parameter()] [int] $ApiVersion, @@ -93,8 +117,15 @@ function New-ServiceNowSession { BaseUri = ('https://{0}/api/now{1}' -f $Url, $version) } - switch ($PSCmdLet.ParameterSetName) { - 'OAuth' { + if ( $PSBoundParameters.ContainsKey('Proxy') ) { + $newSession.Add('Proxy', $Proxy) + if ( $PSBoundParameters.ContainsKey('ProxyCredential') ) { + $newSession.Add('ProxyCredential', $ProxyCredential) + } + } + + switch -Wildcard ($PSCmdLet.ParameterSetName) { + 'OAuth*' { $params = @{ Uri = 'https://{0}/oauth_token.do' -f $Url Body = @{ @@ -107,19 +138,30 @@ function New-ServiceNowSession { Method = 'Post' } + # need to add this manually here, in addition to above, since we're making a rest call before our session is created + if ( $PSBoundParameters.ContainsKey('Proxy') ) { + $params.Add('Proxy', $Proxy) + if ( $PSBoundParameters.ContainsKey('ProxyCredential') ) { + $params.Add('ProxyCredential', $ProxyCredential) + } else { + $params.Add('ProxyUseDefaultCredentials', $true) + } + } + + $token = Invoke-RestMethod @params $newSession.Add('AccessToken', $token.access_token) $newSession.Add('RefreshToken', $token.refresh_token) } - 'AccessToken' { + + 'AccessToken*' { $newSession.Add('AccessToken', $AccessToken) } - 'BasicAuth' { + + 'BasicAuth*' { $newSession.Add('Credential', $Credential) } - 'SSO' { - } Default { } diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 0c8ee65..d003a94 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.0.0' +ModuleVersion = '2.1.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From abb4486711a44ec12576269f25f18380d4fe5986 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 13 Apr 2021 15:42:10 -0400 Subject: [PATCH 197/348] cleanup --- ServiceNow/Public/New-ServiceNowSession.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index eb4b8c6..9ca0f86 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -148,7 +148,6 @@ function New-ServiceNowSession { } } - $token = Invoke-RestMethod @params $newSession.Add('AccessToken', $token.access_token) $newSession.Add('RefreshToken', $token.refresh_token) From b23f62bef5ef70ba49c11dfcadabb5e310878883 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 13 Apr 2021 15:48:04 -0400 Subject: [PATCH 198/348] changelog update --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e233cee..0ae796f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## v2.1 -- Add proxy support, [#97](https://github.com/Snow-Shell/servicenow-powershell/issues/97). Thanks, @mhackethal! +- Add proxy support to `New-ServiceNowSession`, [#97](https://github.com/Snow-Shell/servicenow-powershell/issues/97). ## v2.0 - Although still in the module for backward compatibility, `Set-ServiceNowAuth` is being replaced with `New-ServiceNowSession`. With this comes OAuth support, removal of global variables, and much more folks have asked for. The ability to provide credentials directly to functions has been retained for this release, but will be deprecated in a future release in favor of using `New-ServiceNowSession`. From 49f465c7f420d069b63fb8e2c323e6f80ed82f02 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 13 Apr 2021 18:09:55 -0400 Subject: [PATCH 199/348] Update Readme.md --- Readme.md | 78 ++++++------------------------------------------------- 1 file changed, 8 insertions(+), 70 deletions(-) diff --git a/Readme.md b/Readme.md index 80137d3..ff11a42 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ # ServiceNow -[![GitHub release](https://img.shields.io/github/release/Snow-Shell/servicenow-powershell.svg)](https://github.com/Snow-Shell/servicenow-powershell/releases/latest) [![GitHub license](https://img.shields.io/github/license/Snow-Shell/servicenow-powershell.svg)](LICENSE) ![Test Coverage](https://img.shields.io/badge/coverage-75%25-yellow.svg) +[![GitHub release](https://img.shields.io/github/release/Snow-Shell/servicenow-powershell.svg)](https://github.com/Snow-Shell/servicenow-powershell/releases/latest) [![GitHub license](https://img.shields.io/github/license/Snow-Shell/servicenow-powershell.svg)](LICENSE) 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. @@ -16,28 +16,6 @@ Building on the great work the community has done thus far, a lot of new updates - Pipeline support added to many functions - Standardizing on coding between all functions -## Version 1 - -The module has been renamed from PSServiceNow to ServiceNow for version 1. This change moves us away from the reserved "PS" prefix. Since the name change is a major change for the user base and the project was never incremented to v1 we've taken the opportunity to label it such. - -In addition to the name change the following high level changes have been made: - -Back End: - -* The module structure has been updated to individual files for each function. -* The build process has been migrated from MAKE to psake with support of the BuildHelpers module. -* Pester testing has been expanded to cover more scenarios. -* Improved code formatting, removed aliases, fixed file encoding. - -The gains are marginal in some aspects, but intended to allow for better management in the future. - -Front End: - -* The following fields are now returned in the DateTime format instead of string: 'closed_at','expected_start','follow_up','opened_at','sys_created_on','sys_updated_on','work_end','work_start' [v1.0.1 Update: This process now attempts to format the property as DateTime based off your local culture settings, a universal `yyyy-MM-dd HH:mm:ss` format, and finally leaves the property as a string if those two convert attempts fail]. -* The formatting of returned data has been updated across all the `Get` functions except `Get-ServiceNowTable`. This means you'll see a handful of default properties returned and can use `Format-List` or `Select-Object` to view all other properties associated with the object. - -These changes should improve your ability to filter on the right, especially by DateTime, as well as return more information in general. - ## Requirements Requires PowerShell 3.0 or above as this is when `Invoke-RestMethod` was introduced. @@ -50,38 +28,26 @@ Requires authorization in your ServiceNow tenant. Due to the custom nature of S ## Usage -Download the [latest release](https://github.com/Snow-Shell/servicenow-powershell/releases/latest) and extract the .psm1 and .psd1 files to your PowerShell profile directory (i.e. the `Modules` directory under wherever `$profile` points to in your PS console) and run: -`Import-Module ServiceNow` -Once you've done this, all the cmdlets will be at your disposal, you can see a full list using `Get-Command -Module ServiceNow`. +The ServiceNow module should be installed from the PowerShell Gallery with `install-module ServiceNow`. -### Example - Using Set-ServiceNowAuth +### Creating a new session ```PowerShell -Set-ServiceNowAuth -url InstanceName.service-now.com -Credentials (Get-Credential) +New-ServiceNowSession -url InstanceName.service-now.com -Credentials (Get-Credential) ``` -The URL should be the instance name portion of the FQDN for your instance. If you browse to `https://yourinstance.service-now.com` the URL required for the module is `yourinstance.service-now.com`. +This example is using basic authentication, but OAuth is available as well; see the built-in help for `New-ServiceNowSession`. All examples below assume a new session has already been created. ### Example - Retrieving an Incident Containing the Word 'PowerShell' ```PowerShell -Import-Module ServiceNow -Set-ServiceNowAuth Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} ``` -### Example - Retrieving an Incident Containing the Word 'PowerShell' While Passing Authentication - -```PowerShell -Import-Module ServiceNow -Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} -ServiceNowCredential $PSCredential -ServiceNowURL $ServiceNowURL -``` - ### Example - Update a Ticket ```PowerShell -$Incident = Get-ServiceNowIncident -Limit 1 -MatchContains @{short_description='PowerShell'} -Update-ServiceNowIncident -SysID $Incident.Sys_ID -Values @{comments='Updated via PowerShell'} +Get-ServiceNowIncident -Limit 1 -MatchContains @{short_description='PowerShell'} | Update-ServiceNowIncident -Values @{comments='Updated via PowerShell'} ``` ### Example - Creating a Incident with custom table entries @@ -102,41 +68,13 @@ The module can use the `Connection` parameter in conjunction with the included ` The `Connection` parameter accepts a hashtable object that requires a username, password, and ServiceNowURL. -## Functions - -* Add-ServiceNowAttachment -* Get-ServiceNowAttachment -* Get-ServiceNowAttachmentDetail -* Get-ServiceNowChangeRequest -* Get-ServiceNowConfigurationItem -* Get-ServiceNowIncident -* Get-ServiceNowRequest -* Get-ServiceNowRequestItem -* Get-ServiceNowTable -* Get-ServiceNowTableEntry -* Get-ServiceNowUser -* Get-ServiceNowUserGroup -* New-ServiceNowChangeRequest -* New-ServiceNowIncident -* New-ServiceNowSession -* New-ServiceNowQuery -* New-ServiceNowTableEntry -* Remove-ServiceNowAttachment -* Remove-ServiceNowTableEntry -* Test-ServiceNowAuthIsSet -* Update-ServiceNowChangeRequest -* Update-ServiceNowIncident -* Update-ServiceNowNumber -* Update-ServiceNowRequestItem -* Update-ServiceNowTableEntry - ## Tests -This module comes with [Pester](https://github.com/pester/Pester/) tests for unit testing. +This module comes with limited [Pester](https://github.com/pester/Pester/) tests for unit testing. ## Scope & Contributing -This module has been created as an abstraction layer to suit my immediate requirements. Contributions are gratefully received however, so please feel free to submit a pull request with additional features or amendments. +Contributions are gratefully received, so please feel free to submit a pull request with additional features or amendments. ## Authors From 33bd6449fcaf46d5871d7d750e231765497f3f22 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 19 Apr 2021 21:55:55 -0400 Subject: [PATCH 200/348] add advanced filtering --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 9 + ServiceNow/Public/Get-ServiceNowRecord.ps1 | 77 ++++++++ .../Public/Get-ServiceNowTableEntry.ps1 | 22 +-- ServiceNow/Public/New-ServiceNowQuery.ps1 | 183 ++++++++++++++++-- ServiceNow/Public/New-ServiceNowSession.ps1 | 12 ++ ServiceNow/ServiceNow.psd1 | 4 +- ServiceNow/ServiceNow.psm1 | 16 +- ServiceNow/config/main.json | 137 +++++++++++++ 8 files changed, 422 insertions(+), 38 deletions(-) create mode 100644 ServiceNow/Public/Get-ServiceNowRecord.ps1 create mode 100644 ServiceNow/config/main.json diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 0c0a175..65ca92e 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -39,6 +39,13 @@ function Invoke-ServiceNowRestMethod { [parameter()] [hashtable] $Values, + [parameter()] + [System.Collections.ArrayList] $Filter, + + [parameter()] + [ValidateNotNullOrEmpty()] + [System.Collections.ArrayList] $Order = @('opened_at', 'desc'), + # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) [Parameter()] [string] $Query, @@ -135,6 +142,8 @@ function Invoke-ServiceNowRestMethod { # Populate the query if ($Query) { $Body.sysparm_query = $Query + } else { + $body.sysparm_query = (New-ServiceNowQuery -Filter $Filter -Order $Order) } if ($Properties) { diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 new file mode 100644 index 0000000..9f5b6ac --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -0,0 +1,77 @@ +function Get-ServiceNowRecord { + <# + .SYNOPSIS + Retrieves records for the specified table + .DESCRIPTION + The Get-ServiceNowTable function retrieves records for the specified table + .INPUTS + None + .OUTPUTS + System.Management.Automation.PSCustomObject + .LINK + Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 +#> + + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] + + Param ( + # Name of the table we're querying (e.g. incidents) + [parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string] $Table, + + [parameter(ParameterSetName = 'AutomationFilter')] + [parameter(ParameterSetName = 'SessionFilter')] + [System.Collections.ArrayList] $Filter, + + [parameter(ParameterSetName = 'AutomationFilter')] + [parameter(ParameterSetName = 'SessionFilter')] + [ValidateNotNullOrEmpty()] + [System.Collections.ArrayList] $Order, + + # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) + [Parameter(Mandatory, ParameterSetName = 'AutomationQuery')] + [Parameter(Mandatory, ParameterSetName = 'SessionQuery')] + [string] $Query, + + # Fields to return + [Parameter()] + [Alias('Fields')] + [string[]] $Properties, + + # Whether or not to show human readable display values instead of machine values + [Parameter()] + [ValidateSet('true', 'false', 'all')] + [string] $DisplayValues = 'true', + + [Parameter(Mandatory, ParameterSetName = 'AutomationQuery')] + [parameter(Mandatory, ParameterSetName = 'AutomationFilter')] + [ValidateNotNullOrEmpty()] + [hashtable] $Connection, + + [Parameter(ParameterSetName = 'SessionQuery')] + [Parameter(ParameterSetName = 'SessionFilter')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) + + # $params = $PSBoundParameters + + # Add all provided paging parameters + # ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { + # $params.Add($_, $PSCmdlet.PagingParameters.$_) + # } + + $result = Invoke-ServiceNowRestMethod @PSBoundParameters + + If ( $result -and -not $Properties) { + $type = $script:ServiceNowTable | Where-Object {$_.DbTableName -eq $Table} | Select-Object -ExpandProperty Type + if ($type) { + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } + } + } + + $result +} diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index d09afb6..0d15366 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -23,52 +23,52 @@ function Get-ServiceNowTableEntry { param( # Table containing the entry we're deleting [parameter(Mandatory)] - [string]$Table, + [string] $Table, # Machine name of the field to order by [parameter()] - [string]$OrderBy = 'opened_at', + [string] $OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) [parameter()] [ValidateSet('Desc', 'Asc')] - [string]$OrderDirection = 'Desc', + [string] $OrderDirection = 'Desc', # Maximum number of records to return [parameter()] - [int]$Limit, + [int] $Limit, # Fields to return [Parameter()] [Alias('Fields')] - [string[]]$Properties, + [string[]] $Properties, # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) [parameter()] - [hashtable]$MatchExact = @{}, + [hashtable] $MatchExact = @{}, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) [parameter()] - [hashtable]$MatchContains = @{}, + [hashtable] $MatchContains = @{}, # Whether or not to show human readable display values instead of machine values [parameter()] [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', + [string] $DisplayValues = 'true', [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] [Alias('ServiceNowCredential')] - [PSCredential]$Credential, + [PSCredential] $Credential, [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateScript( { $_ | Test-ServiceNowURL })] [Alias('Url')] - [string]$ServiceNowURL, + [string] $ServiceNowURL, [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [hashtable]$Connection, + [hashtable] $Connection, [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index 93c2020..e36a799 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -18,41 +18,189 @@ function New-ServiceNowQuery { String #> - # This function doesn't change state. Doesn't justify ShouldProcess functionality - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions','')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', 'No state is actually changing')] [CmdletBinding()] [OutputType([System.String])] param( # Machine name of the field to order by - [parameter()] - [string]$OrderBy='opened_at', + [parameter(ParameterSetName = 'Basic')] + [string] $OrderBy = 'opened_at', # Direction of ordering (Desc/Asc) - [parameter()] + [parameter(ParameterSetName = 'Basic')] [ValidateSet("Desc", "Asc")] - [string]$OrderDirection='Desc', + [string] $OrderDirection = 'Desc', # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter()] - [hashtable]$MatchExact, + [parameter(ParameterSetName = 'Basic')] + [hashtable] $MatchExact, # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter()] - [hashtable]$MatchContains + [parameter(ParameterSetName = 'Basic')] + [hashtable] $MatchContains, + + [parameter(ParameterSetName = 'Advanced')] + [System.Collections.ArrayList] $Filter, + + [parameter(ParameterSetName = 'Advanced')] + [ValidateNotNullOrEmpty()] + [System.Collections.ArrayList] $Order = @('opened_at', 'desc') + ) - Try { + Write-Verbose ('{0} - {1}' -f $MyInvocation.MyCommand, $PSCmdlet.ParameterSetName) + + if ( $PSCmdlet.ParameterSetName -eq 'Advanced' ) { + if ( $Filter ) { + $filterList = $Filter + # see if we're working with 1 array or multidimensional array + # we're looking for multidimensional so convert if not + if ($Filter[0].GetType().Name -eq 'String') { + $filterList = @(, $Filter) + } + + $query = for ($i = 0; $i -lt $filterList.Count; $i++) { + $thisFilter = $filterList[$i] + + # allow passing of string instead of array + # useful for joins + if ($thisFilter.GetType().Name -eq 'String') { + $thisFilter = @(, $thisFilter) + } + + switch ($thisFilter.Count) { + 0 { + # nothing to see here + Continue + } + + 1 { + # should be a join + + switch ($thisFilter[0]) { + 'and' { + '^' + } + + 'or' { + '^OR' + } + + 'group' { + '^NQ' + } + + Default { + throw "Unsupported join operator '$($thisFilter[0])'. 'and', 'or', and 'group' are supported." + } + } + + # make sure we don't end on a join + if ( $i -eq $filterList.Count - 1) { + throw '$Filter cannot end with a join' + } + } + + 2 { + # should be a non-value operator + $thisOperator = $script:ServiceNowOperator | Where-Object { $_.Name -eq $thisFilter[1] } + if ( -not $thisOperator ) { + throw ('Operator ''{0}'' is not valid' -f $thisFilter[1]) + } + if ( $thisOperator.RequiresValue ) { + throw ('Value not provided, {0} {1} ?' -f $thisFilter[0], $thisOperator.QueryOperator) + } + '{0}{1}' -f $thisFilter[0], $thisOperator.QueryOperator + } + + 3 { + # should be key operator value + $thisOperator = $script:ServiceNowOperator | Where-Object { $_.Name -eq $thisFilter[1] } + if ( -not $thisOperator ) { + throw ('Operator ''{0}'' is not valid', $thisFilter[1]) + } + '{0}{1}{2}' -f $thisFilter[0], $thisOperator.QueryOperator, $thisFilter[2] + } + + Default { + throw ('Too many items for {0}, see the help' -f $thisFilter[0]) + } + } + } + } + + # force query to an array in case we only got one item and its a string + # otherwise below add to query won't work as expected + $query = @($query) + + if ($query) { + $query += '^' + } + + $orderList = $Order + # see if we're working with 1 array or multidimensional array + # we're looking for multidimensional so convert if not + if ($Order[0].GetType().Name -eq 'String') { + $orderList = @(, $Order) + } + + $query += for ($i = 0; $i -lt $orderList.Count; $i++) { + $thisOrder = $orderList[$i] + if ( $orderList.Count -gt 1 -and $i -gt 0 ) { + '^' + } + + switch ($thisOrder.Count) { + 0 { + # nothing to see here + Continue + } + + 1 { + # should be field, default to ascending + 'ORDERBY' + $thisOrder[0] + } + + 2 { + switch ($thisOrder[1]) { + 'asc' { + 'ORDERBY' + } + + 'desc' { + 'ORDERBYDESC' + } + + Default { + throw "Invalid order direction '$_'. Provide either 'asc' or 'desc'." + } + } + $thisOrder[0] + } + + Default { + throw ('Too many items for {0}, see the help' -f $thisOrder[0]) + } + } + } + + $query -join '' + + } else { + # Basic parameter set + # Create StringBuilder $Query = New-Object System.Text.StringBuilder # Start the query off with a order direction - $Order = Switch ($OrderDirection) { - 'Asc' {'ORDERBY'; break} - Default {'ORDERBYDESC'} + $direction = Switch ($OrderDirection) { + 'Asc' { 'ORDERBY'; break } + Default { 'ORDERBYDESC' } } - [void]$Query.Append($Order) + [void]$Query.Append($direction) # Add OrderBy [void]$Query.Append($OrderBy) @@ -76,7 +224,4 @@ function New-ServiceNowQuery { # Output StringBuilder to string $Query.ToString() } - Catch { - Write-Error $PSItem - } -} +} \ No newline at end of file diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 9ca0f86..b1a35c2 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -166,6 +166,18 @@ function New-ServiceNowSession { } } + $cmdbParams = @{ + Table = 'sys_db_object' + Query = 'nameSTARTSWITHcmdb_ci' + Properties = 'name', 'sys_id', 'label' + First = 10000 + ServiceNowSession = $newSession + } + $ci = Get-ServiceNowTable @cmdbParams -ErrorAction SilentlyContinue + if ( $ci ) { + $newSession.Add('CmdbClasses', $ci) + } + Write-Verbose ($newSession | ConvertTo-Json) if ( $PassThru ) { diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index d003a94..d83cefd 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -59,10 +59,10 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module -FunctionsToExport = @('New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') + FunctionsToExport = @('Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') # Variables to export from this module - VariablesToExport = 'ServiceNowSession' + VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator' # List of all modules packaged with this module # ModuleList = @() diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index fd144c3..080315b 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -4,18 +4,22 @@ param() Write-Verbose $PSScriptRoot +$config = ConvertFrom-Json (Get-Content "$PSScriptRoot\Config\main.json" -Raw) +$Script:ServiceNowOperator = $config.FilterOperators +$script:ServiceNowTable = $config.Tables + +Export-ModuleMember -Variable ServiceNowOperator + Write-Verbose 'Import everything in sub folders folder' -foreach($Folder in @('Private', 'Public')) -{ +foreach ($Folder in @('Private', 'Public')) { $Root = Join-Path -Path $PSScriptRoot -ChildPath $Folder - if(Test-Path -Path $Root) - { + if (Test-Path -Path $Root) { Write-Verbose "processing folder $Root" $Files = Get-ChildItem -Path $Root -Filter *.ps1 -Recurse # dot source each file - $Files | Where-Object{ $_.name -NotLike '*.Tests.ps1'} | - ForEach-Object {Write-Verbose $_.basename; . $PSItem.FullName} + $Files | Where-Object { $_.name -NotLike '*.Tests.ps1' } | + ForEach-Object { Write-Verbose $_.basename; . $PSItem.FullName } } } diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json new file mode 100644 index 0000000..ee4fa56 --- /dev/null +++ b/ServiceNow/config/main.json @@ -0,0 +1,137 @@ +{ + "Tables": [ + { + "Name": "Incident", + "DbTableName": "incident", + "Type": "ServiceNow.Incident" + }, + { + "Name": "Change Request", + "DbTableName": "change_request", + "Type": "ServiceNow.ChangeRequest" + }, + { + "Name": "Configuration Item", + "DbTableName": "cmdb_ci", + "Type": "ServiceNow.ConfigurationItem" + }, + { + "Name": "Request", + "DbTableName": "sc_request", + "Type": "ServiceNow.Request" + }, + { + "Name": "Request Item", + "DbTableName": "sc_req_item", + "Type": "ServiceNow.RequestItem" + }, + { + "Name": "User", + "DbTableName": "sys_user", + "Type": "ServiceNow.UserAndUserGroup" + }, + { + "Name": "User Group", + "DbTableName": "sys_user_group", + "Type": "ServiceNow.UserAndUserGroup" + } + ], + "FilterOperators": [ + { + "Name": "-eq", + "QueryOperator": "=", + "Description": "is equal to", + "RequiresValue": true + }, + { + "Name": "-ne", + "QueryOperator": "!=", + "Description": "is not equal to", + "RequiresValue": true + }, + { + "Name": "=''", + "QueryOperator": "ISEMPTY", + "Description": "field has no value", + "RequiresValue": false + }, + { + "Name": "=\"\"", + "QueryOperator": "ISEMPTY", + "Description": "field has no value", + "RequiresValue": false + }, + { + "Name": "!=''", + "QueryOperator": "ISNOTEMPTY", + "Description": "field has any value", + "RequiresValue": false + }, + { + "Name": "!=\"\"", + "QueryOperator": "ISNOTEMPTY", + "Description": "field has any value", + "RequiresValue": false + }, + { + "Name": "-like", + "QueryOperator": "LIKE", + "Description": "string is found anywhere in field", + "RequiresValue": true + }, + { + "Name": "-notlike", + "QueryOperator": "NOTLIKE", + "Description": "string is not found anywhere in field", + "RequiresValue": true + }, + { + "Name": "-in", + "QueryOperator": "IN", + "Description": "field is populated by one of the values", + "RequiresValue": true + }, + { + "Name": "-notin", + "QueryOperator": "NOTIN", + "Description": "field is populated by any value except for these", + "RequiresValue": true + }, + { + "Name": "lt", + "QueryOperator": "<", + "Description": "", + "RequiresValue": true + }, + { + "Name": "le", + "QueryOperator": "<=", + "Description": "", + "RequiresValue": true + }, + { + "Name": "gt", + "QueryOperator": ">", + "Description": "", + "RequiresValue": true + }, + { + "Name": "ge", + "QueryOperator": ">=", + "Description": "", + "RequiresValue": true + }, + { + "Name": ".startswith", + "QueryOperator": "STARTSWITH", + "Description": "", + "RequiresValue": true + }, + { + "Name": ".endswith", + "QueryOperator": "%", + "Description": "", + "RequiresValue": true + } + ] +} \ No newline at end of file From 3ab8104ff6b8ac03d09450ef0d2a54e235a2e2a8 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 19 Apr 2021 22:59:14 -0400 Subject: [PATCH 201/348] rename order to sort, help updates --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 4 +- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 2 +- ServiceNow/Public/New-ServiceNowQuery.ps1 | 83 ++++++++++++++----- 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 65ca92e..526e9f4 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -44,7 +44,7 @@ function Invoke-ServiceNowRestMethod { [parameter()] [ValidateNotNullOrEmpty()] - [System.Collections.ArrayList] $Order = @('opened_at', 'desc'), + [System.Collections.ArrayList] $Sort = @('opened_at', 'desc'), # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) [Parameter()] @@ -143,7 +143,7 @@ function Invoke-ServiceNowRestMethod { if ($Query) { $Body.sysparm_query = $Query } else { - $body.sysparm_query = (New-ServiceNowQuery -Filter $Filter -Order $Order) + $body.sysparm_query = (New-ServiceNowQuery -Filter $Filter -Sort $Sort) } if ($Properties) { diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 9f5b6ac..72c0681 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -29,7 +29,7 @@ function Get-ServiceNowRecord { [parameter(ParameterSetName = 'AutomationFilter')] [parameter(ParameterSetName = 'SessionFilter')] [ValidateNotNullOrEmpty()] - [System.Collections.ArrayList] $Order, + [System.Collections.ArrayList] $Sort, # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) [Parameter(Mandatory, ParameterSetName = 'AutomationQuery')] diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index e36a799..009ded4 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -1,22 +1,61 @@ +<# +.SYNOPSIS + Build query string for api call + +.DESCRIPTION + Build query string for api call, there are basic and advanced methods; see the different parameter sets. + + Basic allows you to look for exact matches as well as fields that are like a value; these are all and'd together. + You can also sort your results, ascending or descending, by 1 field. + + Advanced allows you to perform the complete set of operations that ServiceNow has (mostly). + The comparison operators have been made to mimic powershell itself so the code should be easy to understand. + You can use a very large set of comparison operators (see the script variable ServiceNowOperator), + and, or, and grouping joins, as well as multiple sorting parameters. + +.PARAMETER Filter + Array or multidimensional array of fields and values to filter on. + Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group. + For a complete list of comparison operators, see $script:ServiceNowOperator. + See the examples. + +.PARAMETER Sort + Array or multidimensional array of fields to sort on. + Each array should be of the format @(field, asc/desc). + +.EXAMPLE + New-ServiceNowQuery -MatchExact @{field_name=value} + Get query string where field name exactly matches the value + +.EXAMPLE + New-ServiceNowQuery -MatchContains @{field_name=value} + Get query string where field name contains the value + +.EXAMPLE + New-ServiceNowQuery -Filter @('state', '-eq', '1'), 'or', @('short_description','-like', 'powershell') + Get query string where state equals New or short description contains the word powershell + +.EXAMPLE + $filter = @('state', '-eq', '1'), + 'and', + @('short_description','-like', 'powershell'), + 'group', + @('state', '-eq', '2') + PS > New-ServiceNowQuery -Filter $filter + Get query string where state equals New and short description contains the word powershell or state equals In Progress. + The first 2 filters are combined and then or'd against the last. + +.EXAMPLE + New-ServiceNowQuery -Filter @('state', '-eq', '1') -Sort @('opened_at', 'desc'), @('state') + Get query string where state equals New and first sort by the field opened_at descending and then sort by the field state ascending + +.INPUTS + None + +.OUTPUTS + String +#> function New-ServiceNowQuery { - <# - .SYNOPSIS - Build query string for api call - .DESCRIPTION - Build query string for api call - .EXAMPLE - New-ServiceNowQuery -MatchExact @{field_name=value} - - Get query string where field name exactly matches the value - .EXAMPLE - New-ServiceNowQuery -MatchContains @{field_name=value} - - Get query string where field name contains the value - .INPUTS - None - .OUTPUTS - String - #> [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', 'No state is actually changing')] @@ -46,7 +85,7 @@ function New-ServiceNowQuery { [parameter(ParameterSetName = 'Advanced')] [ValidateNotNullOrEmpty()] - [System.Collections.ArrayList] $Order = @('opened_at', 'desc') + [System.Collections.ArrayList] $Sort ) @@ -139,11 +178,11 @@ function New-ServiceNowQuery { $query += '^' } - $orderList = $Order + $orderList = $Sort # see if we're working with 1 array or multidimensional array # we're looking for multidimensional so convert if not - if ($Order[0].GetType().Name -eq 'String') { - $orderList = @(, $Order) + if ($Sort[0].GetType().Name -eq 'String') { + $orderList = @(, $Sort) } $query += for ($i = 0; $i -lt $orderList.Count; $i++) { From ace634bf461d12adb6ee27e9f2db7be74d0038e1 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 19 Apr 2021 23:20:39 -0400 Subject: [PATCH 202/348] help updates --- ServiceNow/Public/New-ServiceNowQuery.ps1 | 10 ++++++++-- ServiceNow/config/main.json | 20 ++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index 009ded4..78eeea7 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -8,7 +8,7 @@ Basic allows you to look for exact matches as well as fields that are like a value; these are all and'd together. You can also sort your results, ascending or descending, by 1 field. - Advanced allows you to perform the complete set of operations that ServiceNow has (mostly). + Advanced allows you to perform the (almost) complete set of operations that ServiceNow has. The comparison operators have been made to mimic powershell itself so the code should be easy to understand. You can use a very large set of comparison operators (see the script variable ServiceNowOperator), and, or, and grouping joins, as well as multiple sorting parameters. @@ -16,8 +16,10 @@ .PARAMETER Filter Array or multidimensional array of fields and values to filter on. Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group. - For a complete list of comparison operators, see $script:ServiceNowOperator. + For a complete list of comparison operators, see $script:ServiceNowOperator and use Name in your filter. See the examples. + Also, see https://docs.servicenow.com/bundle/quebec-platform-user-interface/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html + for how to represent dates. .PARAMETER Sort Array or multidimensional array of fields to sort on. @@ -49,6 +51,10 @@ New-ServiceNowQuery -Filter @('state', '-eq', '1') -Sort @('opened_at', 'desc'), @('state') Get query string where state equals New and first sort by the field opened_at descending and then sort by the field state ascending +.EXAMPLE + New-ServiceNowQuery -Filter @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') + Get query string where the record was opened in the last 30 days + .INPUTS None diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index ee4fa56..ef5945c 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -98,39 +98,39 @@ "RequiresValue": true }, { - "Name": "lt", + "Name": "-lt", "QueryOperator": "<", - "Description": "", + "Description": "field is less than the value. can be used with dates to represent prior to the value.", "RequiresValue": true }, { - "Name": "le", + "Name": "-le", "QueryOperator": "<=", - "Description": "", + "Description": "field is less than or equal to the value. can be used with dates to represent prior to or the day of the value.", "RequiresValue": true }, { - "Name": "gt", + "Name": "-gt", "QueryOperator": ">", - "Description": "", + "Description": "field is greater than the value. can be used with dates to represent after the value.", "RequiresValue": true }, { - "Name": "ge", + "Name": "-ge", "QueryOperator": ">=", - "Description": "", + "Description": "field is greater than or equal to the value. can be used with dates to represent after or the day of the value.", "RequiresValue": true }, { "Name": ".startswith", "QueryOperator": "STARTSWITH", - "Description": "", + "Description": "field starts with the value", "RequiresValue": true }, { "Name": ".endswith", "QueryOperator": "%", - "Description": "", + "Description": "field ends with the value", "RequiresValue": true } ] From b8f603e6d59047e9916e6e9538f13019d0bd4b55 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 20 Apr 2021 20:34:01 -0400 Subject: [PATCH 203/348] config property rename --- ServiceNow/config/main.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index ef5945c..9a16e47 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -1,38 +1,38 @@ { "Tables": [ { - "Name": "Incident", - "DbTableName": "incident", + "Name": "incident", + "CommonName": "Incident", "Type": "ServiceNow.Incident" }, { - "Name": "Change Request", - "DbTableName": "change_request", + "Name": "change_request", + "CommonName": "Change Request", "Type": "ServiceNow.ChangeRequest" }, { - "Name": "Configuration Item", - "DbTableName": "cmdb_ci", + "Name": "cmdb_ci", + "CommonName": "Configuration Item", "Type": "ServiceNow.ConfigurationItem" }, { - "Name": "Request", - "DbTableName": "sc_request", + "Name": "sc_request", + "CommonName": "Request", "Type": "ServiceNow.Request" }, { - "Name": "Request Item", - "DbTableName": "sc_req_item", + "Name": "sc_req_item", + "CommonName": "Request Item", "Type": "ServiceNow.RequestItem" }, { - "Name": "User", - "DbTableName": "sys_user", + "Name": "sys_user", + "CommonName": "User", "Type": "ServiceNow.UserAndUserGroup" }, { - "Name": "User Group", - "DbTableName": "sys_user_group", + "Name": "sys_user_group", + "CommonName": "User Group", "Type": "ServiceNow.UserAndUserGroup" } ], From 8b5d875d2ef21bae757347d9320e6aff86e18331 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 20 Apr 2021 20:34:30 -0400 Subject: [PATCH 204/348] help updates --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 109 ++++++++++++++------ ServiceNow/Public/New-ServiceNowQuery.ps1 | 10 +- ServiceNow/Public/New-ServiceNowSession.ps1 | 23 +++-- 3 files changed, 92 insertions(+), 50 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 72c0681..2bdbc22 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -1,27 +1,86 @@ -function Get-ServiceNowRecord { - <# - .SYNOPSIS - Retrieves records for the specified table - .DESCRIPTION - The Get-ServiceNowTable function retrieves records for the specified table - .INPUTS - None - .OUTPUTS - System.Management.Automation.PSCustomObject - .LINK - Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html - Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 +<# +.SYNOPSIS + Retrieves records for the specified table + +.DESCRIPTION + Retrieve records from any table with the option to filter, sort, and choose fields. + Given you know the table name, you shouldn't need any other 'Get-' function. + +.PARAMETER Table + Name of the table to be queried + +.PARAMETER Properties + Limit the fields returned to this list + +.PARAMETER Filter + Array or multidimensional array of fields and values to filter on. + Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group'. + For a complete list of comparison operators, see $script:ServiceNowOperator and use Name in your filter. + See the examples. + Also, see https://docs.servicenow.com/bundle/quebec-platform-user-interface/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html + for how to represent date values with javascript. + +.PARAMETER Sort + Array or multidimensional array of fields to sort on. + Each array should be of the format @(field, asc/desc). + +.PARAMETER DisplayValues + Option to display values for reference fields. + 'false' will only retrieve the reference + 'true' will only retrieve the underlying value + 'all' will retrieve both. This is helpful when trying to translate values for a query. + +.PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + +.PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. + +.EXAMPLE + Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1'), 'or', @('short_description','-like', 'powershell') + Get incident records where state equals New or short description contains the word powershell + +.EXAMPLE + $filter = @('state', '-eq', '1'), + 'and', + @('short_description','-like', 'powershell'), + 'group', + @('state', '-eq', '2') + PS > Get-ServiceNowRecord -Table incident -Filter $filter + Get incident records where state equals New and short description contains the word powershell or state equals In Progress. + The first 2 filters are combined and then or'd against the last. + +.EXAMPLE + Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Sort @('opened_at', 'desc'), @('state') + Get incident records where state equals New and first sort by the field opened_at descending and then sort by the field state ascending + +.EXAMPLE + Get-ServiceNowRecord -Table incident -Filter @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') + Get incident records opened in the last 30 days + +.INPUTS + None + +.OUTPUTS + System.Management.Automation.PSCustomObject + +.LINK + https://docs.servicenow.com/bundle/quebec-platform-user-interface/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html #> +function Get-ServiceNowRecord { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'SessionFilter', SupportsPaging)] Param ( - # Name of the table we're querying (e.g. incidents) [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Table, + [Parameter()] + [Alias('Fields')] + [string[]] $Properties, + [parameter(ParameterSetName = 'AutomationFilter')] [parameter(ParameterSetName = 'SessionFilter')] [System.Collections.ArrayList] $Filter, @@ -31,17 +90,6 @@ function Get-ServiceNowRecord { [ValidateNotNullOrEmpty()] [System.Collections.ArrayList] $Sort, - # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [Parameter(Mandatory, ParameterSetName = 'AutomationQuery')] - [Parameter(Mandatory, ParameterSetName = 'SessionQuery')] - [string] $Query, - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]] $Properties, - - # Whether or not to show human readable display values instead of machine values [Parameter()] [ValidateSet('true', 'false', 'all')] [string] $DisplayValues = 'true', @@ -57,17 +105,10 @@ function Get-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - # $params = $PSBoundParameters - - # Add all provided paging parameters - # ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { - # $params.Add($_, $PSCmdlet.PagingParameters.$_) - # } - $result = Invoke-ServiceNowRestMethod @PSBoundParameters If ( $result -and -not $Properties) { - $type = $script:ServiceNowTable | Where-Object {$_.DbTableName -eq $Table} | Select-Object -ExpandProperty Type + $type = $script:ServiceNowTable | Where-Object {$_.Name -eq $Table} | Select-Object -ExpandProperty Type if ($type) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } } diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index 78eeea7..e8f82f2 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -15,7 +15,7 @@ .PARAMETER Filter Array or multidimensional array of fields and values to filter on. - Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group. + Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group'. For a complete list of comparison operators, see $script:ServiceNowOperator and use Name in your filter. See the examples. Also, see https://docs.servicenow.com/bundle/quebec-platform-user-interface/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html @@ -101,7 +101,7 @@ function New-ServiceNowQuery { if ( $Filter ) { $filterList = $Filter # see if we're working with 1 array or multidimensional array - # we're looking for multidimensional so convert if not + # we want multidimensional so convert if not if ($Filter[0].GetType().Name -eq 'String') { $filterList = @(, $Filter) } @@ -149,7 +149,7 @@ function New-ServiceNowQuery { } 2 { - # should be a non-value operator + # should be a non-value operator, eg. ='' / ISEMPTY $thisOperator = $script:ServiceNowOperator | Where-Object { $_.Name -eq $thisFilter[1] } if ( -not $thisOperator ) { throw ('Operator ''{0}'' is not valid' -f $thisFilter[1]) @@ -161,7 +161,7 @@ function New-ServiceNowQuery { } 3 { - # should be key operator value + # should be field operator value $thisOperator = $script:ServiceNowOperator | Where-Object { $_.Name -eq $thisFilter[1] } if ( -not $thisOperator ) { throw ('Operator ''{0}'' is not valid', $thisFilter[1]) @@ -186,7 +186,7 @@ function New-ServiceNowQuery { $orderList = $Sort # see if we're working with 1 array or multidimensional array - # we're looking for multidimensional so convert if not + # we want multidimensional so convert if not if ($Sort[0].GetType().Name -eq 'String') { $orderList = @(, $Sort) } diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index b1a35c2..1693917 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -166,17 +166,18 @@ function New-ServiceNowSession { } } - $cmdbParams = @{ - Table = 'sys_db_object' - Query = 'nameSTARTSWITHcmdb_ci' - Properties = 'name', 'sys_id', 'label' - First = 10000 - ServiceNowSession = $newSession - } - $ci = Get-ServiceNowTable @cmdbParams -ErrorAction SilentlyContinue - if ( $ci ) { - $newSession.Add('CmdbClasses', $ci) - } + # TODO + # $cmdbParams = @{ + # Table = 'sys_db_object' + # Query = 'nameSTARTSWITHcmdb_ci' + # Properties = 'name', 'sys_id', 'label' + # First = 10000 + # ServiceNowSession = $newSession + # } + # $ci = Get-ServiceNowTable @cmdbParams -ErrorAction SilentlyContinue + # if ( $ci ) { + # $newSession.Add('CmdbClasses', $ci) + # } Write-Verbose ($newSession | ConvertTo-Json) From 7fa927c364b473974b56198e3b303d32ef5b5be2 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 20 Apr 2021 20:54:52 -0400 Subject: [PATCH 205/348] release prep --- CHANGELOG.md | 6 ++++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ae796f..0a91284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.2 +- Add advanced filtering and sorting. Initially implemented with `New-ServiceNowQuery` and `Get-ServiceNowRecord`. Filter with many different comparison operators as well as 'and', 'or', and 'group'ing. Sort ascending or desending against multiple fields. Comparison operators are the same as PowerShell for ease of use. +- Add `Get-ServiceNowRecord`. This function implements the new advanced filtering and sorting. As long as you know your table name, this can replace all other Get functions. +- Enumerate implemented tables and advanced filtering operators in a json config to easily manage going forward; make available via script session variables. +Be able to reference type names from this config per table, removing the need to have separate Get functions for every table. + ## v2.1 - Add proxy support to `New-ServiceNowSession`, [#97](https://github.com/Snow-Shell/servicenow-powershell/issues/97). diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index d83cefd..7e32a3e 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.1.0' +ModuleVersion = '2.2.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From e8ded23117ba52f30533258e596c78a221127972 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 20 Apr 2021 20:56:16 -0400 Subject: [PATCH 206/348] typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a91284..9e715f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ## v2.2 -- Add advanced filtering and sorting. Initially implemented with `New-ServiceNowQuery` and `Get-ServiceNowRecord`. Filter with many different comparison operators as well as 'and', 'or', and 'group'ing. Sort ascending or desending against multiple fields. Comparison operators are the same as PowerShell for ease of use. +- Add advanced filtering and sorting. Initially implemented with `New-ServiceNowQuery` and `Get-ServiceNowRecord`. Filter with many different comparison operators as well as 'and', 'or', and 'group'ing. Sort ascending or descending against multiple fields. Comparison operators are the same as PowerShell for ease of use. - Add `Get-ServiceNowRecord`. This function implements the new advanced filtering and sorting. As long as you know your table name, this can replace all other Get functions. - Enumerate implemented tables and advanced filtering operators in a json config to easily manage going forward; make available via script session variables. Be able to reference type names from this config per table, removing the need to have separate Get functions for every table. From be4446c752442928f41493674398eb706aee22e7 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 20 Apr 2021 21:01:24 -0400 Subject: [PATCH 207/348] typo --- ServiceNow/config/main.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 9a16e47..cb28ac5 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -76,13 +76,13 @@ { "Name": "-like", "QueryOperator": "LIKE", - "Description": "string is found anywhere in field", + "Description": "value is found anywhere in field", "RequiresValue": true }, { "Name": "-notlike", "QueryOperator": "NOTLIKE", - "Description": "string is not found anywhere in field", + "Description": "value is not found anywhere in field", "RequiresValue": true }, { From a56573e0234008639f2cef60e8e66808a0fe7a54 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 21 Apr 2021 19:33:54 -0400 Subject: [PATCH 208/348] add catalog task type --- ServiceNow/ServiceNow.format.ps1xml | 53 +++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index cb3401f..db97bd6 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -308,5 +308,58 @@ + + ServiceNow.CatalogTask + + ServiceNow.CatalogTask + + + + + + 12 + + + + 8 + + + + 21 + + + + 25 + + + + 12 + + + + + + + number + + + state + + + opened_at + + + short_description + + + + $_.request_item.display_value + + + + + + + From 20d6bfeb16471efd7e2fd09c4e5cb2a8975567a0 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 21 Apr 2021 19:35:40 -0400 Subject: [PATCH 209/348] rename to correct class name --- ...NowRequestItem.ps1 => Get-ServiceNowRequestedItem.ps1} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename ServiceNow/Public/{Get-ServiceNowRequestItem.ps1 => Get-ServiceNowRequestedItem.ps1} (90%) diff --git a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 similarity index 90% rename from ServiceNow/Public/Get-ServiceNowRequestItem.ps1 rename to ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 index 7a1b1f6..c2fdf01 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 @@ -1,13 +1,13 @@ -function Get-ServiceNowRequestItem { +function Get-ServiceNowRequestedItem { <# .SYNOPSIS - Query for Request Item (RITM) tickets. + Query for Requested Item (RITM) tickets. .DESCRIPTION - Query for Request Item (RITM) tickets from the sc_req_item table. + Query for Requested Item (RITM) tickets from the sc_req_item table. .EXAMPLE - Get-ServiceNowRequestItem -MatchExact @{number='RITM0000001'} + Get-ServiceNowRequestedItem -MatchExact @{number='RITM0000001'} Return the details for RITM0000001 From ef7aef975bedf97d0009ebd5f10465f4c83e3b76 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 21 Apr 2021 19:37:18 -0400 Subject: [PATCH 210/348] help and other minor updates --- CHANGELOG.md | 9 +++-- Readme.md | 39 ++++++++++++++++--- .../Private/Invoke-ServiceNowRestMethod.ps1 | 13 ++++++- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 9 +++-- ServiceNow/Public/New-ServiceNowSession.ps1 | 25 +++++++++--- ServiceNow/ServiceNow.psd1 | 2 +- ServiceNow/ServiceNow.psm1 | 11 +++++- ServiceNow/config/main.json | 19 +++++---- 8 files changed, 96 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e715f6..3007eca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ ## v2.2 -- Add advanced filtering and sorting. Initially implemented with `New-ServiceNowQuery` and `Get-ServiceNowRecord`. Filter with many different comparison operators as well as 'and', 'or', and 'group'ing. Sort ascending or descending against multiple fields. Comparison operators are the same as PowerShell for ease of use. +- Add advanced filtering and sorting. Initially implemented with `New-ServiceNowQuery` and `Get-ServiceNowRecord`. Filter with many different comparison operators as well as 'and', 'or', and 'group'ing. Sort ascending or descending against multiple fields. Comparison operators are the same as PowerShell for ease of use. Please use the GitHub Discussions section to provide feedback, thoughts, etc. - Add `Get-ServiceNowRecord`. This function implements the new advanced filtering and sorting. As long as you know your table name, this can replace all other Get functions. -- Enumerate implemented tables and advanced filtering operators in a json config to easily manage going forward; make available via script session variables. -Be able to reference type names from this config per table, removing the need to have separate Get functions for every table. +- Enumerate implemented tables and advanced filtering operators in a json config to easily manage going forward; make available via script scoped variables. +Be able to reference types from this config per table, removing the need to have separate Get functions for every table. +- Add type for catalog task +- Fix error when getting an empty result from the api and performing a type lookup +- Rename `Get-ServiceNowRequestItem` to `Get-ServiceNowRequestedItem` which is the actual name. Function alias created. ## v2.1 - Add proxy support to `New-ServiceNowSession`, [#97](https://github.com/Snow-Shell/servicenow-powershell/issues/97). diff --git a/Readme.md b/Readme.md index ff11a42..b3a46cf 100644 --- a/Readme.md +++ b/Readme.md @@ -18,7 +18,7 @@ Building on the great work the community has done thus far, a lot of new updates ## Requirements -Requires PowerShell 3.0 or above as this is when `Invoke-RestMethod` was introduced. +Requires PowerShell 5.1 or above. Requires authorization in your ServiceNow tenant. Due to the custom nature of ServiceNow your organization may have REST access restricted. The following are some tips to ask for if you're having to go to your admin for access: @@ -32,25 +32,52 @@ The ServiceNow module should be installed from the PowerShell Gallery with `inst ### Creating a new session +Creating a new session will create a script scoped variable `$ServiceNowSession` which will be used by default in other functions. + +Basic authentication with just a credential... ```PowerShell -New-ServiceNowSession -url InstanceName.service-now.com -Credentials (Get-Credential) +$params @{ + Url = 'instance.service-now.com' + Credential = $userCred +} +New-ServiceNowSession @params ``` -This example is using basic authentication, but OAuth is available as well; see the built-in help for `New-ServiceNowSession`. All examples below assume a new session has already been created. +Oauth authentication with user credential as well as application/client credential. The application/client credential can be found in the System OAuth->Application Registry section of ServiceNow. +```PowerShell +$params @{ + Url = 'instance.service-now.com' + Credential = $userCred + ClientCredential = $clientCred +} +New-ServiceNowSession @params +``` -### Example - Retrieving an Incident Containing the Word 'PowerShell' +All examples below assume a new session has already been created. + +### Getting incidents opened in the last 30 days +```PowerShell +$filter = @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') +Get-ServiceNowRecord -Table incident -Filter $filter +``` + +### Retrieving an Incident Containing the Word 'PowerShell' ```PowerShell Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} ``` +or new with v2.2 +```PowerShell +Get-ServiceNowRecord -Table incident -Filter @('short_description','-eq','PowerShell') +``` -### Example - Update a Ticket +### Update a Ticket ```PowerShell Get-ServiceNowIncident -Limit 1 -MatchContains @{short_description='PowerShell'} | Update-ServiceNowIncident -Values @{comments='Updated via PowerShell'} ``` -### Example - Creating a Incident with custom table entries +### Creating an Incident with custom table entries ```PowerShell $IncidentParams = @{Caller = "UserName" diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 526e9f4..d493792 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -23,6 +23,7 @@ function Invoke-ServiceNowRestMethod { # Name of the table we're querying (e.g. incidents) [parameter(Mandatory, ParameterSetName = 'Table')] [ValidateNotNullOrEmpty()] + [Alias('sys_class_name')] [string] $Table, [parameter(ParameterSetName = 'Table')] @@ -89,7 +90,15 @@ function Invoke-ServiceNowRestMethod { $params.ContentType = 'application/json' if ( $Table ) { - $params.Uri += "/table/$Table" + # table can either be the actual table name or class name + # look up the actual table name + $tableName = $script:ServiceNowTable | Where-Object { $_.Name -eq $Table -or $_.ClassName -eq $Table } | Select-Object -ExpandProperty Name + # if not in our lookup, just use the table name as provided + if ( -not $tableName ) { + $tableName = $Table + } + + $params.Uri += "/table/$tableName" if ( $SysId ) { $params.Uri += "/$SysId" } @@ -168,7 +177,7 @@ function Invoke-ServiceNowRestMethod { switch ($Method) { 'Get' { - if ( $response.result ) { + if ( $response.PSobject.Properties.Name -contains "result" ) { $result = $response | Select-Object -ExpandProperty result $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 2bdbc22..18e9361 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -7,7 +7,7 @@ Given you know the table name, you shouldn't need any other 'Get-' function. .PARAMETER Table - Name of the table to be queried + Name of the table to be queried, by either table name or class name .PARAMETER Properties Limit the fields returned to this list @@ -55,8 +55,8 @@ Get incident records where state equals New and first sort by the field opened_at descending and then sort by the field state ascending .EXAMPLE - Get-ServiceNowRecord -Table incident -Filter @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') - Get incident records opened in the last 30 days + Get-ServiceNowRecord -Table 'change request' -Filter @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') + Get change requests opened in the last 30 days. Use class name as opposed to table name. .INPUTS None @@ -75,6 +75,7 @@ function Get-ServiceNowRecord { Param ( [parameter(Mandatory)] [ValidateNotNullOrEmpty()] + [Alias('sys_class_name')] [string] $Table, [Parameter()] @@ -108,7 +109,7 @@ function Get-ServiceNowRecord { $result = Invoke-ServiceNowRestMethod @PSBoundParameters If ( $result -and -not $Properties) { - $type = $script:ServiceNowTable | Where-Object {$_.Name -eq $Table} | Select-Object -ExpandProperty Type + $type = $script:ServiceNowTable | Where-Object {$_.Name -eq $Table -or $_.ClassName -eq $Table} | Select-Object -ExpandProperty Type if ($type) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } } diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 1693917..0dc6cfa 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -166,17 +166,30 @@ function New-ServiceNowSession { } } - # TODO + # Write-Verbose 'Retrieving list of classes for this instance. This will take a few seconds...' # $cmdbParams = @{ # Table = 'sys_db_object' - # Query = 'nameSTARTSWITHcmdb_ci' + # # Query = 'nameSTARTSWITHcmdb_ci' # Properties = 'name', 'sys_id', 'label' - # First = 10000 + # First = 100000 # ServiceNowSession = $newSession # } - # $ci = Get-ServiceNowTable @cmdbParams -ErrorAction SilentlyContinue - # if ( $ci ) { - # $newSession.Add('CmdbClasses', $ci) + + # $class = Get-ServiceNowTable @cmdbParams -ErrorAction SilentlyContinue | + # Select-Object @{ + # 'n' = 'Name' + # 'e' = { $_.name } + # }, + # @{ + # 'n' = 'SysId' + # 'e' = { $_.sys_id } + # }, + # @{ + # 'n' = 'ClassName' + # 'e' = { $_.label } + # } + # if ( $class ) { + # $newSession.Add('Classes', $class) # } Write-Verbose ($newSession | ConvertTo-Json) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 7e32a3e..ddaac9d 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -59,7 +59,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module - FunctionsToExport = @('Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') + FunctionsToExport = @('Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') # Variables to export from this module VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator' diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 080315b..ea3627e 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -1,4 +1,3 @@ -#Requires -Version 3.0 [cmdletbinding()] param() @@ -26,4 +25,12 @@ foreach ($Folder in @('Private', 'Public')) { Export-ModuleMember -Function (Get-ChildItem -Path "$PSScriptRoot\Public\*.ps1").BaseName $Script:ServiceNowSession = @{} -Export-ModuleMember -Variable ServiceNowSession \ No newline at end of file +Export-ModuleMember -Variable ServiceNowSession + +$aliases = @{ + 'Get-ServiceNowRequestItem' = 'Get-ServiceNowRequestedItem' +} +$aliases.GetEnumerator() | ForEach-Object { + Set-Alias -Name $_.Key -Value $_.Value +} +Export-ModuleMember -Alias * diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index cb28ac5..9a242c8 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -2,38 +2,43 @@ "Tables": [ { "Name": "incident", - "CommonName": "Incident", + "ClassName": "Incident", "Type": "ServiceNow.Incident" }, { "Name": "change_request", - "CommonName": "Change Request", + "ClassName": "Change Request", "Type": "ServiceNow.ChangeRequest" }, { "Name": "cmdb_ci", - "CommonName": "Configuration Item", + "ClassName": "Configuration Item", "Type": "ServiceNow.ConfigurationItem" }, { "Name": "sc_request", - "CommonName": "Request", + "ClassName": "Request", "Type": "ServiceNow.Request" }, { "Name": "sc_req_item", - "CommonName": "Request Item", + "ClassName": "Request Item", "Type": "ServiceNow.RequestItem" }, { "Name": "sys_user", - "CommonName": "User", + "ClassName": "User", "Type": "ServiceNow.UserAndUserGroup" }, { "Name": "sys_user_group", - "CommonName": "User Group", + "ClassName": "User Group", "Type": "ServiceNow.UserAndUserGroup" + }, + { + "Name": "sc_task", + "ClassName": "Catalog Task", + "Type": "ServiceNow.CatalogTask" } ], "FilterOperators": [ From dfb05cd6f1e50207c96263e1710a7157d9f19b04 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 21 Apr 2021 19:55:25 -0400 Subject: [PATCH 211/348] request->requested --- ...NowRequestItem.ps1 => Update-ServiceNowRequestedItem.ps1} | 2 +- ServiceNow/ServiceNow.psd1 | 2 +- ServiceNow/ServiceNow.psm1 | 5 +++-- ServiceNow/config/main.json | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) rename ServiceNow/Public/{Update-ServiceNowRequestItem.ps1 => Update-ServiceNowRequestedItem.ps1} (96%) diff --git a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 b/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 similarity index 96% rename from ServiceNow/Public/Update-ServiceNowRequestItem.ps1 rename to ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 index 884dcf3..01f30c8 100644 --- a/ServiceNow/Public/Update-ServiceNowRequestItem.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 @@ -72,7 +72,7 @@ function Update-ServiceNowRequestItem { ServiceNowSession = $ServiceNowSession } - If ($PSCmdlet.ShouldProcess("Request Item $SysID", 'Update values')) { + If ($PSCmdlet.ShouldProcess("Requested Item $SysID", 'Update values')) { $response = Invoke-ServiceNowRestMethod @params if ( $PassThru.IsPresent ) { $response diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index ddaac9d..1f64875 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -62,7 +62,7 @@ NestedModules = @() FunctionsToExport = @('Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') # Variables to export from this module - VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator' + VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable' # List of all modules packaged with this module # ModuleList = @() diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index ea3627e..fcb3c26 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -7,7 +7,7 @@ $config = ConvertFrom-Json (Get-Content "$PSScriptRoot\Config\main.json" -Raw) $Script:ServiceNowOperator = $config.FilterOperators $script:ServiceNowTable = $config.Tables -Export-ModuleMember -Variable ServiceNowOperator +Export-ModuleMember -Variable ServiceNowOperator, ServiceNowTable Write-Verbose 'Import everything in sub folders folder' foreach ($Folder in @('Private', 'Public')) { @@ -28,7 +28,8 @@ $Script:ServiceNowSession = @{} Export-ModuleMember -Variable ServiceNowSession $aliases = @{ - 'Get-ServiceNowRequestItem' = 'Get-ServiceNowRequestedItem' + 'Get-ServiceNowRequestItem' = 'Get-ServiceNowRequestedItem' + 'Update-ServiceNowRequestItem' = 'Update-ServiceNowRequestedItem' } $aliases.GetEnumerator() | ForEach-Object { Set-Alias -Name $_.Key -Value $_.Value diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 9a242c8..2002ef0 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -22,7 +22,7 @@ }, { "Name": "sc_req_item", - "ClassName": "Request Item", + "ClassName": "Requested Item", "Type": "ServiceNow.RequestItem" }, { From acc0a5f68511f95e34b4fec58813986a879f56c0 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 21 Apr 2021 20:12:13 -0400 Subject: [PATCH 212/348] changelog update --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3007eca..81526ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ Be able to reference types from this config per table, removing the need to have separate Get functions for every table. - Add type for catalog task - Fix error when getting an empty result from the api and performing a type lookup -- Rename `Get-ServiceNowRequestItem` to `Get-ServiceNowRequestedItem` which is the actual name. Function alias created. +- Rename `RequestItem` to `RequestedItem` which is the actual name. Function aliases created. ## v2.1 - Add proxy support to `New-ServiceNowSession`, [#97](https://github.com/Snow-Shell/servicenow-powershell/issues/97). From 53adff043e5d979662591837e10f7ae8fc4cb510 Mon Sep 17 00:00:00 2001 From: Nate Scherer <376408+natescherer@users.noreply.github.com> Date: Tue, 27 Apr 2021 11:52:05 -0400 Subject: [PATCH 213/348] Replace [System.Web.MimeMapping]::GetMimeMapping with static hash of mimetypes to support PowerShell 7 --- .../Public/Add-ServiceNowAttachment.ps1 | 639 +++++++++++++++++- 1 file changed, 637 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 842a7bf..576aeb2 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -114,8 +114,643 @@ Function Add-ServiceNowAttachment { ForEach ($Object in $File) { $FileData = Get-ChildItem $Object -ErrorAction Stop If (-not $ContentType) { - Add-Type -AssemblyName 'System.Web' - $ContentType = [System.Web.MimeMapping]::GetMimeMapping($FileData.FullName) + $ContentTypeHash = @{ + ".323" = "text/h323" + ".3g2" = "video/3gpp2" + ".3gp" = "video/3gpp" + ".3gp2" = "video/3gpp2" + ".3gpp" = "video/3gpp" + ".7z" = "application/x-7z-compressed" + ".aa" = "audio/audible" + ".AAC" = "audio/aac" + ".aaf" = "application/octet-stream" + ".aax" = "audio/vnd.audible.aax" + ".ac3" = "audio/ac3" + ".aca" = "application/octet-stream" + ".accda" = "application/msaccess.addin" + ".accdb" = "application/msaccess" + ".accdc" = "application/msaccess.cab" + ".accde" = "application/msaccess" + ".accdr" = "application/msaccess.runtime" + ".accdt" = "application/msaccess" + ".accdw" = "application/msaccess.webapplication" + ".accft" = "application/msaccess.ftemplate" + ".acx" = "application/internet-property-stream" + ".AddIn" = "text/xml" + ".ade" = "application/msaccess" + ".adobebridge" = "application/x-bridge-url" + ".adp" = "application/msaccess" + ".ADT" = "audio/vnd.dlna.adts" + ".ADTS" = "audio/aac" + ".afm" = "application/octet-stream" + ".ai" = "application/postscript" + ".aif" = "audio/aiff" + ".aifc" = "audio/aiff" + ".aiff" = "audio/aiff" + ".air" = "application/vnd.adobe.air-application-installer-package+zip" + ".amc" = "application/mpeg" + ".anx" = "application/annodex" + ".apk" = "application/vnd.android.package-archive" + ".apng" = "image/apng" + ".application" = "application/x-ms-application" + ".art" = "image/x-jg" + ".asa" = "application/xml" + ".asax" = "application/xml" + ".ascx" = "application/xml" + ".asd" = "application/octet-stream" + ".asf" = "video/x-ms-asf" + ".ashx" = "application/xml" + ".asi" = "application/octet-stream" + ".asm" = "text/plain" + ".asmx" = "application/xml" + ".aspx" = "application/xml" + ".asr" = "video/x-ms-asf" + ".asx" = "video/x-ms-asf" + ".atom" = "application/atom+xml" + ".au" = "audio/basic" + ".avci" = "image/avci" + ".avcs" = "image/avcs" + ".avi" = "video/x-msvideo" + ".avif" = "image/avif" + ".avifs" = "image/avif-sequence" + ".axa" = "audio/annodex" + ".axs" = "application/olescript" + ".axv" = "video/annodex" + ".bas" = "text/plain" + ".bcpio" = "application/x-bcpio" + ".bin" = "application/octet-stream" + ".bmp" = "image/bmp" + ".c" = "text/plain" + ".cab" = "application/octet-stream" + ".caf" = "audio/x-caf" + ".calx" = "application/vnd.ms-office.calx" + ".cat" = "application/vnd.ms-pki.seccat" + ".cc" = "text/plain" + ".cd" = "text/plain" + ".cdda" = "audio/aiff" + ".cdf" = "application/x-cdf" + ".cer" = "application/x-x509-ca-cert" + ".cfg" = "text/plain" + ".chm" = "application/octet-stream" + ".class" = "application/x-java-applet" + ".clp" = "application/x-msclip" + ".cmd" = "text/plain" + ".cmx" = "image/x-cmx" + ".cnf" = "text/plain" + ".cod" = "image/cis-cod" + ".config" = "application/xml" + ".contact" = "text/x-ms-contact" + ".coverage" = "application/xml" + ".cpio" = "application/x-cpio" + ".cpp" = "text/plain" + ".crd" = "application/x-mscardfile" + ".crl" = "application/pkix-crl" + ".crt" = "application/x-x509-ca-cert" + ".cs" = "text/plain" + ".csdproj" = "text/plain" + ".csh" = "application/x-csh" + ".csproj" = "text/plain" + ".css" = "text/css" + ".csv" = "text/csv" + ".cur" = "application/octet-stream" + ".czx" = "application/x-czx" + ".cxx" = "text/plain" + ".dat" = "application/octet-stream" + ".datasource" = "application/xml" + ".dbproj" = "text/plain" + ".dcr" = "application/x-director" + ".def" = "text/plain" + ".deploy" = "application/octet-stream" + ".der" = "application/x-x509-ca-cert" + ".dgml" = "application/xml" + ".dib" = "image/bmp" + ".dif" = "video/x-dv" + ".dir" = "application/x-director" + ".disco" = "text/xml" + ".divx" = "video/divx" + ".dll" = "application/x-msdownload" + ".dll.config" = "text/xml" + ".dlm" = "text/dlm" + ".doc" = "application/msword" + ".docm" = "application/vnd.ms-word.document.macroEnabled.12" + ".docx" = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ".dot" = "application/msword" + ".dotm" = "application/vnd.ms-word.template.macroEnabled.12" + ".dotx" = "application/vnd.openxmlformats-officedocument.wordprocessingml.template" + ".dsp" = "application/octet-stream" + ".dsw" = "text/plain" + ".dtd" = "text/xml" + ".dtsConfig" = "text/xml" + ".dv" = "video/x-dv" + ".dvi" = "application/x-dvi" + ".dwf" = "drawing/x-dwf" + ".dwg" = "application/acad" + ".dwp" = "application/octet-stream" + ".dxf" = "application/x-dxf" + ".dxr" = "application/x-director" + ".eml" = "message/rfc822" + ".emf" = "image/emf" + ".emz" = "application/octet-stream" + ".eot" = "application/vnd.ms-fontobject" + ".eps" = "application/postscript" + ".es" = "application/ecmascript" + ".etl" = "application/etl" + ".etx" = "text/x-setext" + ".evy" = "application/envoy" + ".exe" = "application/vnd.microsoft.portable-executable" + ".exe.config" = "text/xml" + ".f4v" = "video/mp4" + ".fdf" = "application/vnd.fdf" + ".fif" = "application/fractals" + ".filters" = "application/xml" + ".fla" = "application/octet-stream" + ".flac" = "audio/flac" + ".flr" = "x-world/x-vrml" + ".flv" = "video/x-flv" + ".fsscript" = "application/fsharp-script" + ".fsx" = "application/fsharp-script" + ".generictest" = "application/xml" + ".gif" = "image/gif" + ".gpx" = "application/gpx+xml" + ".group" = "text/x-ms-group" + ".gsm" = "audio/x-gsm" + ".gtar" = "application/x-gtar" + ".gz" = "application/x-gzip" + ".h" = "text/plain" + ".hdf" = "application/x-hdf" + ".hdml" = "text/x-hdml" + ".heic" = "image/heic" + ".heics" = "image/heic-sequence" + ".heif" = "image/heif" + ".heifs" = "image/heif-sequence" + ".hhc" = "application/x-oleobject" + ".hhk" = "application/octet-stream" + ".hhp" = "application/octet-stream" + ".hlp" = "application/winhlp" + ".hpp" = "text/plain" + ".hqx" = "application/mac-binhex40" + ".hta" = "application/hta" + ".htc" = "text/x-component" + ".htm" = "text/html" + ".html" = "text/html" + ".htt" = "text/webviewhtml" + ".hxa" = "application/xml" + ".hxc" = "application/xml" + ".hxd" = "application/octet-stream" + ".hxe" = "application/xml" + ".hxf" = "application/xml" + ".hxh" = "application/octet-stream" + ".hxi" = "application/octet-stream" + ".hxk" = "application/xml" + ".hxq" = "application/octet-stream" + ".hxr" = "application/octet-stream" + ".hxs" = "application/octet-stream" + ".hxt" = "text/html" + ".hxv" = "application/xml" + ".hxw" = "application/octet-stream" + ".hxx" = "text/plain" + ".i" = "text/plain" + ".ical" = "text/calendar" + ".icalendar" = "text/calendar" + ".ico" = "image/x-icon" + ".ics" = "text/calendar" + ".idl" = "text/plain" + ".ief" = "image/ief" + ".ifb" = "text/calendar" + ".iii" = "application/x-iphone" + ".inc" = "text/plain" + ".inf" = "application/octet-stream" + ".ini" = "text/plain" + ".inl" = "text/plain" + ".ins" = "application/x-internet-signup" + ".ipa" = "application/x-itunes-ipa" + ".ipg" = "application/x-itunes-ipg" + ".ipproj" = "text/plain" + ".ipsw" = "application/x-itunes-ipsw" + ".iqy" = "text/x-ms-iqy" + ".isp" = "application/x-internet-signup" + ".isma" = "application/octet-stream" + ".ismv" = "application/octet-stream" + ".ite" = "application/x-itunes-ite" + ".itlp" = "application/x-itunes-itlp" + ".itms" = "application/x-itunes-itms" + ".itpc" = "application/x-itunes-itpc" + ".IVF" = "video/x-ivf" + ".jar" = "application/java-archive" + ".java" = "application/octet-stream" + ".jck" = "application/liquidmotion" + ".jcz" = "application/liquidmotion" + ".jfif" = "image/pjpeg" + ".jnlp" = "application/x-java-jnlp-file" + ".jpb" = "application/octet-stream" + ".jpe" = "image/jpeg" + ".jpeg" = "image/jpeg" + ".jpg" = "image/jpeg" + ".js" = "application/javascript" + ".json" = "application/json" + ".jsx" = "text/jscript" + ".jsxbin" = "text/plain" + ".latex" = "application/x-latex" + ".library-ms" = "application/windows-library+xml" + ".lit" = "application/x-ms-reader" + ".loadtest" = "application/xml" + ".lpk" = "application/octet-stream" + ".lsf" = "video/x-la-asf" + ".lst" = "text/plain" + ".lsx" = "video/x-la-asf" + ".lzh" = "application/octet-stream" + ".m13" = "application/x-msmediaview" + ".m14" = "application/x-msmediaview" + ".m1v" = "video/mpeg" + ".m2t" = "video/vnd.dlna.mpeg-tts" + ".m2ts" = "video/vnd.dlna.mpeg-tts" + ".m2v" = "video/mpeg" + ".m3u" = "audio/x-mpegurl" + ".m3u8" = "audio/x-mpegurl" + ".m4a" = "audio/m4a" + ".m4b" = "audio/m4b" + ".m4p" = "audio/m4p" + ".m4r" = "audio/x-m4r" + ".m4v" = "video/x-m4v" + ".mac" = "image/x-macpaint" + ".mak" = "text/plain" + ".man" = "application/x-troff-man" + ".manifest" = "application/x-ms-manifest" + ".map" = "text/plain" + ".master" = "application/xml" + ".mbox" = "application/mbox" + ".mda" = "application/msaccess" + ".mdb" = "application/x-msaccess" + ".mde" = "application/msaccess" + ".mdp" = "application/octet-stream" + ".me" = "application/x-troff-me" + ".mfp" = "application/x-shockwave-flash" + ".mht" = "message/rfc822" + ".mhtml" = "message/rfc822" + ".mid" = "audio/mid" + ".midi" = "audio/mid" + ".mix" = "application/octet-stream" + ".mk" = "text/plain" + ".mk3d" = "video/x-matroska-3d" + ".mka" = "audio/x-matroska" + ".mkv" = "video/x-matroska" + ".mmf" = "application/x-smaf" + ".mno" = "text/xml" + ".mny" = "application/x-msmoney" + ".mod" = "video/mpeg" + ".mov" = "video/quicktime" + ".movie" = "video/x-sgi-movie" + ".mp2" = "video/mpeg" + ".mp2v" = "video/mpeg" + ".mp3" = "audio/mpeg" + ".mp4" = "video/mp4" + ".mp4v" = "video/mp4" + ".mpa" = "video/mpeg" + ".mpe" = "video/mpeg" + ".mpeg" = "video/mpeg" + ".mpf" = "application/vnd.ms-mediapackage" + ".mpg" = "video/mpeg" + ".mpp" = "application/vnd.ms-project" + ".mpv2" = "video/mpeg" + ".mqv" = "video/quicktime" + ".ms" = "application/x-troff-ms" + ".msg" = "application/vnd.ms-outlook" + ".msi" = "application/octet-stream" + ".mso" = "application/octet-stream" + ".mts" = "video/vnd.dlna.mpeg-tts" + ".mtx" = "application/xml" + ".mvb" = "application/x-msmediaview" + ".mvc" = "application/x-miva-compiled" + ".mxf" = "application/mxf" + ".mxp" = "application/x-mmxp" + ".nc" = "application/x-netcdf" + ".nsc" = "video/x-ms-asf" + ".nws" = "message/rfc822" + ".ocx" = "application/octet-stream" + ".oda" = "application/oda" + ".odb" = "application/vnd.oasis.opendocument.database" + ".odc" = "application/vnd.oasis.opendocument.chart" + ".odf" = "application/vnd.oasis.opendocument.formula" + ".odg" = "application/vnd.oasis.opendocument.graphics" + ".odh" = "text/plain" + ".odi" = "application/vnd.oasis.opendocument.image" + ".odl" = "text/plain" + ".odm" = "application/vnd.oasis.opendocument.text-master" + ".odp" = "application/vnd.oasis.opendocument.presentation" + ".ods" = "application/vnd.oasis.opendocument.spreadsheet" + ".odt" = "application/vnd.oasis.opendocument.text" + ".oga" = "audio/ogg" + ".ogg" = "audio/ogg" + ".ogv" = "video/ogg" + ".ogx" = "application/ogg" + ".one" = "application/onenote" + ".onea" = "application/onenote" + ".onepkg" = "application/onenote" + ".onetmp" = "application/onenote" + ".onetoc" = "application/onenote" + ".onetoc2" = "application/onenote" + ".opus" = "audio/ogg" + ".orderedtest" = "application/xml" + ".osdx" = "application/opensearchdescription+xml" + ".otf" = "application/font-sfnt" + ".otg" = "application/vnd.oasis.opendocument.graphics-template" + ".oth" = "application/vnd.oasis.opendocument.text-web" + ".otp" = "application/vnd.oasis.opendocument.presentation-template" + ".ots" = "application/vnd.oasis.opendocument.spreadsheet-template" + ".ott" = "application/vnd.oasis.opendocument.text-template" + ".oxps" = "application/oxps" + ".oxt" = "application/vnd.openofficeorg.extension" + ".p10" = "application/pkcs10" + ".p12" = "application/x-pkcs12" + ".p7b" = "application/x-pkcs7-certificates" + ".p7c" = "application/pkcs7-mime" + ".p7m" = "application/pkcs7-mime" + ".p7r" = "application/x-pkcs7-certreqresp" + ".p7s" = "application/pkcs7-signature" + ".pbm" = "image/x-portable-bitmap" + ".pcast" = "application/x-podcast" + ".pct" = "image/pict" + ".pcx" = "application/octet-stream" + ".pcz" = "application/octet-stream" + ".pdf" = "application/pdf" + ".pfb" = "application/octet-stream" + ".pfm" = "application/octet-stream" + ".pfx" = "application/x-pkcs12" + ".pgm" = "image/x-portable-graymap" + ".pic" = "image/pict" + ".pict" = "image/pict" + ".pkgdef" = "text/plain" + ".pkgundef" = "text/plain" + ".pko" = "application/vnd.ms-pki.pko" + ".pls" = "audio/scpls" + ".pma" = "application/x-perfmon" + ".pmc" = "application/x-perfmon" + ".pml" = "application/x-perfmon" + ".pmr" = "application/x-perfmon" + ".pmw" = "application/x-perfmon" + ".png" = "image/png" + ".pnm" = "image/x-portable-anymap" + ".pnt" = "image/x-macpaint" + ".pntg" = "image/x-macpaint" + ".pnz" = "image/png" + ".pot" = "application/vnd.ms-powerpoint" + ".potm" = "application/vnd.ms-powerpoint.template.macroEnabled.12" + ".potx" = "application/vnd.openxmlformats-officedocument.presentationml.template" + ".ppa" = "application/vnd.ms-powerpoint" + ".ppam" = "application/vnd.ms-powerpoint.addin.macroEnabled.12" + ".ppm" = "image/x-portable-pixmap" + ".pps" = "application/vnd.ms-powerpoint" + ".ppsm" = "application/vnd.ms-powerpoint.slideshow.macroEnabled.12" + ".ppsx" = "application/vnd.openxmlformats-officedocument.presentationml.slideshow" + ".ppt" = "application/vnd.ms-powerpoint" + ".pptm" = "application/vnd.ms-powerpoint.presentation.macroEnabled.12" + ".pptx" = "application/vnd.openxmlformats-officedocument.presentationml.presentation" + ".prf" = "application/pics-rules" + ".prm" = "application/octet-stream" + ".prx" = "application/octet-stream" + ".ps" = "application/postscript" + ".psc1" = "application/PowerShell" + ".psd" = "application/octet-stream" + ".psess" = "application/xml" + ".psm" = "application/octet-stream" + ".psp" = "application/octet-stream" + ".pst" = "application/vnd.ms-outlook" + ".pub" = "application/x-mspublisher" + ".pwz" = "application/vnd.ms-powerpoint" + ".qht" = "text/x-html-insertion" + ".qhtm" = "text/x-html-insertion" + ".qt" = "video/quicktime" + ".qti" = "image/x-quicktime" + ".qtif" = "image/x-quicktime" + ".qtl" = "application/x-quicktimeplayer" + ".qxd" = "application/octet-stream" + ".ra" = "audio/x-pn-realaudio" + ".ram" = "audio/x-pn-realaudio" + ".rar" = "application/x-rar-compressed" + ".ras" = "image/x-cmu-raster" + ".rat" = "application/rat-file" + ".rc" = "text/plain" + ".rc2" = "text/plain" + ".rct" = "text/plain" + ".rdlc" = "application/xml" + ".reg" = "text/plain" + ".resx" = "application/xml" + ".rf" = "image/vnd.rn-realflash" + ".rgb" = "image/x-rgb" + ".rgs" = "text/plain" + ".rm" = "application/vnd.rn-realmedia" + ".rmi" = "audio/mid" + ".rmp" = "application/vnd.rn-rn_music_package" + ".rmvb" = "application/vnd.rn-realmedia-vbr" + ".roff" = "application/x-troff" + ".rpm" = "audio/x-pn-realaudio-plugin" + ".rqy" = "text/x-ms-rqy" + ".rtf" = "application/rtf" + ".rtx" = "text/richtext" + ".rvt" = "application/octet-stream" + ".ruleset" = "application/xml" + ".s" = "text/plain" + ".safariextz" = "application/x-safari-safariextz" + ".scd" = "application/x-msschedule" + ".scr" = "text/plain" + ".sct" = "text/scriptlet" + ".sd2" = "audio/x-sd2" + ".sdp" = "application/sdp" + ".sea" = "application/octet-stream" + ".searchConnector-ms" = "application/windows-search-connector+xml" + ".setpay" = "application/set-payment-initiation" + ".setreg" = "application/set-registration-initiation" + ".settings" = "application/xml" + ".sgimb" = "application/x-sgimb" + ".sgml" = "text/sgml" + ".sh" = "application/x-sh" + ".shar" = "application/x-shar" + ".shtml" = "text/html" + ".sit" = "application/x-stuffit" + ".sitemap" = "application/xml" + ".skin" = "application/xml" + ".skp" = "application/x-koan" + ".sldm" = "application/vnd.ms-powerpoint.slide.macroEnabled.12" + ".sldx" = "application/vnd.openxmlformats-officedocument.presentationml.slide" + ".slk" = "application/vnd.ms-excel" + ".sln" = "text/plain" + ".slupkg-ms" = "application/x-ms-license" + ".smd" = "audio/x-smd" + ".smi" = "application/octet-stream" + ".smx" = "audio/x-smd" + ".smz" = "audio/x-smd" + ".snd" = "audio/basic" + ".snippet" = "application/xml" + ".snp" = "application/octet-stream" + ".sql" = "application/sql" + ".sol" = "text/plain" + ".sor" = "text/plain" + ".spc" = "application/x-pkcs7-certificates" + ".spl" = "application/futuresplash" + ".spx" = "audio/ogg" + ".src" = "application/x-wais-source" + ".srf" = "text/plain" + ".SSISDeploymentManifest" = "text/xml" + ".ssm" = "application/streamingmedia" + ".sst" = "application/vnd.ms-pki.certstore" + ".stl" = "application/vnd.ms-pki.stl" + ".sv4cpio" = "application/x-sv4cpio" + ".sv4crc" = "application/x-sv4crc" + ".svc" = "application/xml" + ".svg" = "image/svg+xml" + ".swf" = "application/x-shockwave-flash" + ".step" = "application/step" + ".stp" = "application/step" + ".t" = "application/x-troff" + ".tar" = "application/x-tar" + ".tcl" = "application/x-tcl" + ".testrunconfig" = "application/xml" + ".testsettings" = "application/xml" + ".tex" = "application/x-tex" + ".texi" = "application/x-texinfo" + ".texinfo" = "application/x-texinfo" + ".tgz" = "application/x-compressed" + ".thmx" = "application/vnd.ms-officetheme" + ".thn" = "application/octet-stream" + ".tif" = "image/tiff" + ".tiff" = "image/tiff" + ".tlh" = "text/plain" + ".tli" = "text/plain" + ".toc" = "application/octet-stream" + ".tr" = "application/x-troff" + ".trm" = "application/x-msterminal" + ".trx" = "application/xml" + ".ts" = "video/vnd.dlna.mpeg-tts" + ".tsv" = "text/tab-separated-values" + ".ttf" = "application/font-sfnt" + ".tts" = "video/vnd.dlna.mpeg-tts" + ".txt" = "text/plain" + ".u32" = "application/octet-stream" + ".uls" = "text/iuls" + ".user" = "text/plain" + ".ustar" = "application/x-ustar" + ".vb" = "text/plain" + ".vbdproj" = "text/plain" + ".vbk" = "video/mpeg" + ".vbproj" = "text/plain" + ".vbs" = "text/vbscript" + ".vcf" = "text/x-vcard" + ".vcproj" = "application/xml" + ".vcs" = "text/plain" + ".vcxproj" = "application/xml" + ".vddproj" = "text/plain" + ".vdp" = "text/plain" + ".vdproj" = "text/plain" + ".vdx" = "application/vnd.ms-visio.viewer" + ".vml" = "text/xml" + ".vscontent" = "application/xml" + ".vsct" = "text/xml" + ".vsd" = "application/vnd.visio" + ".vsi" = "application/ms-vsi" + ".vsix" = "application/vsix" + ".vsixlangpack" = "text/xml" + ".vsixmanifest" = "text/xml" + ".vsmdi" = "application/xml" + ".vspscc" = "text/plain" + ".vss" = "application/vnd.visio" + ".vsscc" = "text/plain" + ".vssettings" = "text/xml" + ".vssscc" = "text/plain" + ".vst" = "application/vnd.visio" + ".vstemplate" = "text/xml" + ".vsto" = "application/x-ms-vsto" + ".vsw" = "application/vnd.visio" + ".vsx" = "application/vnd.visio" + ".vtt" = "text/vtt" + ".vtx" = "application/vnd.visio" + ".wasm" = "application/wasm" + ".wav" = "audio/wav" + ".wave" = "audio/wav" + ".wax" = "audio/x-ms-wax" + ".wbk" = "application/msword" + ".wbmp" = "image/vnd.wap.wbmp" + ".wcm" = "application/vnd.ms-works" + ".wdb" = "application/vnd.ms-works" + ".wdp" = "image/vnd.ms-photo" + ".webarchive" = "application/x-safari-webarchive" + ".webm" = "video/webm" + ".webp" = "image/webp" + ".webtest" = "application/xml" + ".wiq" = "application/xml" + ".wiz" = "application/msword" + ".wks" = "application/vnd.ms-works" + ".WLMP" = "application/wlmoviemaker" + ".wlpginstall" = "application/x-wlpg-detect" + ".wlpginstall3" = "application/x-wlpg3-detect" + ".wm" = "video/x-ms-wm" + ".wma" = "audio/x-ms-wma" + ".wmd" = "application/x-ms-wmd" + ".wmf" = "application/x-msmetafile" + ".wml" = "text/vnd.wap.wml" + ".wmlc" = "application/vnd.wap.wmlc" + ".wmls" = "text/vnd.wap.wmlscript" + ".wmlsc" = "application/vnd.wap.wmlscriptc" + ".wmp" = "video/x-ms-wmp" + ".wmv" = "video/x-ms-wmv" + ".wmx" = "video/x-ms-wmx" + ".wmz" = "application/x-ms-wmz" + ".woff" = "application/font-woff" + ".woff2" = "application/font-woff2" + ".wpl" = "application/vnd.ms-wpl" + ".wps" = "application/vnd.ms-works" + ".wri" = "application/x-mswrite" + ".wrl" = "x-world/x-vrml" + ".wrz" = "x-world/x-vrml" + ".wsc" = "text/scriptlet" + ".wsdl" = "text/xml" + ".wvx" = "video/x-ms-wvx" + ".x" = "application/directx" + ".xaf" = "x-world/x-vrml" + ".xaml" = "application/xaml+xml" + ".xap" = "application/x-silverlight-app" + ".xbap" = "application/x-ms-xbap" + ".xbm" = "image/x-xbitmap" + ".xdr" = "text/plain" + ".xht" = "application/xhtml+xml" + ".xhtml" = "application/xhtml+xml" + ".xla" = "application/vnd.ms-excel" + ".xlam" = "application/vnd.ms-excel.addin.macroEnabled.12" + ".xlc" = "application/vnd.ms-excel" + ".xld" = "application/vnd.ms-excel" + ".xlk" = "application/vnd.ms-excel" + ".xll" = "application/vnd.ms-excel" + ".xlm" = "application/vnd.ms-excel" + ".xls" = "application/vnd.ms-excel" + ".xlsb" = "application/vnd.ms-excel.sheet.binary.macroEnabled.12" + ".xlsm" = "application/vnd.ms-excel.sheet.macroEnabled.12" + ".xlsx" = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ".xlt" = "application/vnd.ms-excel" + ".xltm" = "application/vnd.ms-excel.template.macroEnabled.12" + ".xltx" = "application/vnd.openxmlformats-officedocument.spreadsheetml.template" + ".xlw" = "application/vnd.ms-excel" + ".xml" = "text/xml" + ".xmp" = "application/octet-stream" + ".xmta" = "application/xml" + ".xof" = "x-world/x-vrml" + ".XOML" = "text/plain" + ".xpm" = "image/x-xpixmap" + ".xps" = "application/vnd.ms-xpsdocument" + ".xrm-ms" = "text/xml" + ".xsc" = "application/xml" + ".xsd" = "text/xml" + ".xsf" = "text/xml" + ".xsl" = "text/xml" + ".xslt" = "text/xml" + ".xsn" = "application/octet-stream" + ".xss" = "application/xml" + ".xspf" = "application/xspf+xml" + ".xtp" = "application/octet-stream" + ".xwd" = "image/x-xwindowdump" + ".z" = "application/x-compress" + ".zip" = "application/zip" + } + $Extension = [IO.Path]::GetExtension($FileData.FullName) + $ContentType = $ContentTypeHash.$Extension } # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot From 390ad95ef4b036722f2560f22b6a212bea647af6 Mon Sep 17 00:00:00 2001 From: Nate Scherer <376408+natescherer@users.noreply.github.com> Date: Wed, 28 Apr 2021 12:19:42 -0400 Subject: [PATCH 214/348] Move mime type mappings to external MimeTypeMap.json file --- .../Public/Add-ServiceNowAttachment.ps1 | 639 +----------------- ServiceNow/config/MimeTypeMap.json | Bin 0 -> 47128 bytes 2 files changed, 4 insertions(+), 635 deletions(-) create mode 100644 ServiceNow/config/MimeTypeMap.json diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 576aeb2..d8801ac 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -114,641 +114,10 @@ Function Add-ServiceNowAttachment { ForEach ($Object in $File) { $FileData = Get-ChildItem $Object -ErrorAction Stop If (-not $ContentType) { - $ContentTypeHash = @{ - ".323" = "text/h323" - ".3g2" = "video/3gpp2" - ".3gp" = "video/3gpp" - ".3gp2" = "video/3gpp2" - ".3gpp" = "video/3gpp" - ".7z" = "application/x-7z-compressed" - ".aa" = "audio/audible" - ".AAC" = "audio/aac" - ".aaf" = "application/octet-stream" - ".aax" = "audio/vnd.audible.aax" - ".ac3" = "audio/ac3" - ".aca" = "application/octet-stream" - ".accda" = "application/msaccess.addin" - ".accdb" = "application/msaccess" - ".accdc" = "application/msaccess.cab" - ".accde" = "application/msaccess" - ".accdr" = "application/msaccess.runtime" - ".accdt" = "application/msaccess" - ".accdw" = "application/msaccess.webapplication" - ".accft" = "application/msaccess.ftemplate" - ".acx" = "application/internet-property-stream" - ".AddIn" = "text/xml" - ".ade" = "application/msaccess" - ".adobebridge" = "application/x-bridge-url" - ".adp" = "application/msaccess" - ".ADT" = "audio/vnd.dlna.adts" - ".ADTS" = "audio/aac" - ".afm" = "application/octet-stream" - ".ai" = "application/postscript" - ".aif" = "audio/aiff" - ".aifc" = "audio/aiff" - ".aiff" = "audio/aiff" - ".air" = "application/vnd.adobe.air-application-installer-package+zip" - ".amc" = "application/mpeg" - ".anx" = "application/annodex" - ".apk" = "application/vnd.android.package-archive" - ".apng" = "image/apng" - ".application" = "application/x-ms-application" - ".art" = "image/x-jg" - ".asa" = "application/xml" - ".asax" = "application/xml" - ".ascx" = "application/xml" - ".asd" = "application/octet-stream" - ".asf" = "video/x-ms-asf" - ".ashx" = "application/xml" - ".asi" = "application/octet-stream" - ".asm" = "text/plain" - ".asmx" = "application/xml" - ".aspx" = "application/xml" - ".asr" = "video/x-ms-asf" - ".asx" = "video/x-ms-asf" - ".atom" = "application/atom+xml" - ".au" = "audio/basic" - ".avci" = "image/avci" - ".avcs" = "image/avcs" - ".avi" = "video/x-msvideo" - ".avif" = "image/avif" - ".avifs" = "image/avif-sequence" - ".axa" = "audio/annodex" - ".axs" = "application/olescript" - ".axv" = "video/annodex" - ".bas" = "text/plain" - ".bcpio" = "application/x-bcpio" - ".bin" = "application/octet-stream" - ".bmp" = "image/bmp" - ".c" = "text/plain" - ".cab" = "application/octet-stream" - ".caf" = "audio/x-caf" - ".calx" = "application/vnd.ms-office.calx" - ".cat" = "application/vnd.ms-pki.seccat" - ".cc" = "text/plain" - ".cd" = "text/plain" - ".cdda" = "audio/aiff" - ".cdf" = "application/x-cdf" - ".cer" = "application/x-x509-ca-cert" - ".cfg" = "text/plain" - ".chm" = "application/octet-stream" - ".class" = "application/x-java-applet" - ".clp" = "application/x-msclip" - ".cmd" = "text/plain" - ".cmx" = "image/x-cmx" - ".cnf" = "text/plain" - ".cod" = "image/cis-cod" - ".config" = "application/xml" - ".contact" = "text/x-ms-contact" - ".coverage" = "application/xml" - ".cpio" = "application/x-cpio" - ".cpp" = "text/plain" - ".crd" = "application/x-mscardfile" - ".crl" = "application/pkix-crl" - ".crt" = "application/x-x509-ca-cert" - ".cs" = "text/plain" - ".csdproj" = "text/plain" - ".csh" = "application/x-csh" - ".csproj" = "text/plain" - ".css" = "text/css" - ".csv" = "text/csv" - ".cur" = "application/octet-stream" - ".czx" = "application/x-czx" - ".cxx" = "text/plain" - ".dat" = "application/octet-stream" - ".datasource" = "application/xml" - ".dbproj" = "text/plain" - ".dcr" = "application/x-director" - ".def" = "text/plain" - ".deploy" = "application/octet-stream" - ".der" = "application/x-x509-ca-cert" - ".dgml" = "application/xml" - ".dib" = "image/bmp" - ".dif" = "video/x-dv" - ".dir" = "application/x-director" - ".disco" = "text/xml" - ".divx" = "video/divx" - ".dll" = "application/x-msdownload" - ".dll.config" = "text/xml" - ".dlm" = "text/dlm" - ".doc" = "application/msword" - ".docm" = "application/vnd.ms-word.document.macroEnabled.12" - ".docx" = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - ".dot" = "application/msword" - ".dotm" = "application/vnd.ms-word.template.macroEnabled.12" - ".dotx" = "application/vnd.openxmlformats-officedocument.wordprocessingml.template" - ".dsp" = "application/octet-stream" - ".dsw" = "text/plain" - ".dtd" = "text/xml" - ".dtsConfig" = "text/xml" - ".dv" = "video/x-dv" - ".dvi" = "application/x-dvi" - ".dwf" = "drawing/x-dwf" - ".dwg" = "application/acad" - ".dwp" = "application/octet-stream" - ".dxf" = "application/x-dxf" - ".dxr" = "application/x-director" - ".eml" = "message/rfc822" - ".emf" = "image/emf" - ".emz" = "application/octet-stream" - ".eot" = "application/vnd.ms-fontobject" - ".eps" = "application/postscript" - ".es" = "application/ecmascript" - ".etl" = "application/etl" - ".etx" = "text/x-setext" - ".evy" = "application/envoy" - ".exe" = "application/vnd.microsoft.portable-executable" - ".exe.config" = "text/xml" - ".f4v" = "video/mp4" - ".fdf" = "application/vnd.fdf" - ".fif" = "application/fractals" - ".filters" = "application/xml" - ".fla" = "application/octet-stream" - ".flac" = "audio/flac" - ".flr" = "x-world/x-vrml" - ".flv" = "video/x-flv" - ".fsscript" = "application/fsharp-script" - ".fsx" = "application/fsharp-script" - ".generictest" = "application/xml" - ".gif" = "image/gif" - ".gpx" = "application/gpx+xml" - ".group" = "text/x-ms-group" - ".gsm" = "audio/x-gsm" - ".gtar" = "application/x-gtar" - ".gz" = "application/x-gzip" - ".h" = "text/plain" - ".hdf" = "application/x-hdf" - ".hdml" = "text/x-hdml" - ".heic" = "image/heic" - ".heics" = "image/heic-sequence" - ".heif" = "image/heif" - ".heifs" = "image/heif-sequence" - ".hhc" = "application/x-oleobject" - ".hhk" = "application/octet-stream" - ".hhp" = "application/octet-stream" - ".hlp" = "application/winhlp" - ".hpp" = "text/plain" - ".hqx" = "application/mac-binhex40" - ".hta" = "application/hta" - ".htc" = "text/x-component" - ".htm" = "text/html" - ".html" = "text/html" - ".htt" = "text/webviewhtml" - ".hxa" = "application/xml" - ".hxc" = "application/xml" - ".hxd" = "application/octet-stream" - ".hxe" = "application/xml" - ".hxf" = "application/xml" - ".hxh" = "application/octet-stream" - ".hxi" = "application/octet-stream" - ".hxk" = "application/xml" - ".hxq" = "application/octet-stream" - ".hxr" = "application/octet-stream" - ".hxs" = "application/octet-stream" - ".hxt" = "text/html" - ".hxv" = "application/xml" - ".hxw" = "application/octet-stream" - ".hxx" = "text/plain" - ".i" = "text/plain" - ".ical" = "text/calendar" - ".icalendar" = "text/calendar" - ".ico" = "image/x-icon" - ".ics" = "text/calendar" - ".idl" = "text/plain" - ".ief" = "image/ief" - ".ifb" = "text/calendar" - ".iii" = "application/x-iphone" - ".inc" = "text/plain" - ".inf" = "application/octet-stream" - ".ini" = "text/plain" - ".inl" = "text/plain" - ".ins" = "application/x-internet-signup" - ".ipa" = "application/x-itunes-ipa" - ".ipg" = "application/x-itunes-ipg" - ".ipproj" = "text/plain" - ".ipsw" = "application/x-itunes-ipsw" - ".iqy" = "text/x-ms-iqy" - ".isp" = "application/x-internet-signup" - ".isma" = "application/octet-stream" - ".ismv" = "application/octet-stream" - ".ite" = "application/x-itunes-ite" - ".itlp" = "application/x-itunes-itlp" - ".itms" = "application/x-itunes-itms" - ".itpc" = "application/x-itunes-itpc" - ".IVF" = "video/x-ivf" - ".jar" = "application/java-archive" - ".java" = "application/octet-stream" - ".jck" = "application/liquidmotion" - ".jcz" = "application/liquidmotion" - ".jfif" = "image/pjpeg" - ".jnlp" = "application/x-java-jnlp-file" - ".jpb" = "application/octet-stream" - ".jpe" = "image/jpeg" - ".jpeg" = "image/jpeg" - ".jpg" = "image/jpeg" - ".js" = "application/javascript" - ".json" = "application/json" - ".jsx" = "text/jscript" - ".jsxbin" = "text/plain" - ".latex" = "application/x-latex" - ".library-ms" = "application/windows-library+xml" - ".lit" = "application/x-ms-reader" - ".loadtest" = "application/xml" - ".lpk" = "application/octet-stream" - ".lsf" = "video/x-la-asf" - ".lst" = "text/plain" - ".lsx" = "video/x-la-asf" - ".lzh" = "application/octet-stream" - ".m13" = "application/x-msmediaview" - ".m14" = "application/x-msmediaview" - ".m1v" = "video/mpeg" - ".m2t" = "video/vnd.dlna.mpeg-tts" - ".m2ts" = "video/vnd.dlna.mpeg-tts" - ".m2v" = "video/mpeg" - ".m3u" = "audio/x-mpegurl" - ".m3u8" = "audio/x-mpegurl" - ".m4a" = "audio/m4a" - ".m4b" = "audio/m4b" - ".m4p" = "audio/m4p" - ".m4r" = "audio/x-m4r" - ".m4v" = "video/x-m4v" - ".mac" = "image/x-macpaint" - ".mak" = "text/plain" - ".man" = "application/x-troff-man" - ".manifest" = "application/x-ms-manifest" - ".map" = "text/plain" - ".master" = "application/xml" - ".mbox" = "application/mbox" - ".mda" = "application/msaccess" - ".mdb" = "application/x-msaccess" - ".mde" = "application/msaccess" - ".mdp" = "application/octet-stream" - ".me" = "application/x-troff-me" - ".mfp" = "application/x-shockwave-flash" - ".mht" = "message/rfc822" - ".mhtml" = "message/rfc822" - ".mid" = "audio/mid" - ".midi" = "audio/mid" - ".mix" = "application/octet-stream" - ".mk" = "text/plain" - ".mk3d" = "video/x-matroska-3d" - ".mka" = "audio/x-matroska" - ".mkv" = "video/x-matroska" - ".mmf" = "application/x-smaf" - ".mno" = "text/xml" - ".mny" = "application/x-msmoney" - ".mod" = "video/mpeg" - ".mov" = "video/quicktime" - ".movie" = "video/x-sgi-movie" - ".mp2" = "video/mpeg" - ".mp2v" = "video/mpeg" - ".mp3" = "audio/mpeg" - ".mp4" = "video/mp4" - ".mp4v" = "video/mp4" - ".mpa" = "video/mpeg" - ".mpe" = "video/mpeg" - ".mpeg" = "video/mpeg" - ".mpf" = "application/vnd.ms-mediapackage" - ".mpg" = "video/mpeg" - ".mpp" = "application/vnd.ms-project" - ".mpv2" = "video/mpeg" - ".mqv" = "video/quicktime" - ".ms" = "application/x-troff-ms" - ".msg" = "application/vnd.ms-outlook" - ".msi" = "application/octet-stream" - ".mso" = "application/octet-stream" - ".mts" = "video/vnd.dlna.mpeg-tts" - ".mtx" = "application/xml" - ".mvb" = "application/x-msmediaview" - ".mvc" = "application/x-miva-compiled" - ".mxf" = "application/mxf" - ".mxp" = "application/x-mmxp" - ".nc" = "application/x-netcdf" - ".nsc" = "video/x-ms-asf" - ".nws" = "message/rfc822" - ".ocx" = "application/octet-stream" - ".oda" = "application/oda" - ".odb" = "application/vnd.oasis.opendocument.database" - ".odc" = "application/vnd.oasis.opendocument.chart" - ".odf" = "application/vnd.oasis.opendocument.formula" - ".odg" = "application/vnd.oasis.opendocument.graphics" - ".odh" = "text/plain" - ".odi" = "application/vnd.oasis.opendocument.image" - ".odl" = "text/plain" - ".odm" = "application/vnd.oasis.opendocument.text-master" - ".odp" = "application/vnd.oasis.opendocument.presentation" - ".ods" = "application/vnd.oasis.opendocument.spreadsheet" - ".odt" = "application/vnd.oasis.opendocument.text" - ".oga" = "audio/ogg" - ".ogg" = "audio/ogg" - ".ogv" = "video/ogg" - ".ogx" = "application/ogg" - ".one" = "application/onenote" - ".onea" = "application/onenote" - ".onepkg" = "application/onenote" - ".onetmp" = "application/onenote" - ".onetoc" = "application/onenote" - ".onetoc2" = "application/onenote" - ".opus" = "audio/ogg" - ".orderedtest" = "application/xml" - ".osdx" = "application/opensearchdescription+xml" - ".otf" = "application/font-sfnt" - ".otg" = "application/vnd.oasis.opendocument.graphics-template" - ".oth" = "application/vnd.oasis.opendocument.text-web" - ".otp" = "application/vnd.oasis.opendocument.presentation-template" - ".ots" = "application/vnd.oasis.opendocument.spreadsheet-template" - ".ott" = "application/vnd.oasis.opendocument.text-template" - ".oxps" = "application/oxps" - ".oxt" = "application/vnd.openofficeorg.extension" - ".p10" = "application/pkcs10" - ".p12" = "application/x-pkcs12" - ".p7b" = "application/x-pkcs7-certificates" - ".p7c" = "application/pkcs7-mime" - ".p7m" = "application/pkcs7-mime" - ".p7r" = "application/x-pkcs7-certreqresp" - ".p7s" = "application/pkcs7-signature" - ".pbm" = "image/x-portable-bitmap" - ".pcast" = "application/x-podcast" - ".pct" = "image/pict" - ".pcx" = "application/octet-stream" - ".pcz" = "application/octet-stream" - ".pdf" = "application/pdf" - ".pfb" = "application/octet-stream" - ".pfm" = "application/octet-stream" - ".pfx" = "application/x-pkcs12" - ".pgm" = "image/x-portable-graymap" - ".pic" = "image/pict" - ".pict" = "image/pict" - ".pkgdef" = "text/plain" - ".pkgundef" = "text/plain" - ".pko" = "application/vnd.ms-pki.pko" - ".pls" = "audio/scpls" - ".pma" = "application/x-perfmon" - ".pmc" = "application/x-perfmon" - ".pml" = "application/x-perfmon" - ".pmr" = "application/x-perfmon" - ".pmw" = "application/x-perfmon" - ".png" = "image/png" - ".pnm" = "image/x-portable-anymap" - ".pnt" = "image/x-macpaint" - ".pntg" = "image/x-macpaint" - ".pnz" = "image/png" - ".pot" = "application/vnd.ms-powerpoint" - ".potm" = "application/vnd.ms-powerpoint.template.macroEnabled.12" - ".potx" = "application/vnd.openxmlformats-officedocument.presentationml.template" - ".ppa" = "application/vnd.ms-powerpoint" - ".ppam" = "application/vnd.ms-powerpoint.addin.macroEnabled.12" - ".ppm" = "image/x-portable-pixmap" - ".pps" = "application/vnd.ms-powerpoint" - ".ppsm" = "application/vnd.ms-powerpoint.slideshow.macroEnabled.12" - ".ppsx" = "application/vnd.openxmlformats-officedocument.presentationml.slideshow" - ".ppt" = "application/vnd.ms-powerpoint" - ".pptm" = "application/vnd.ms-powerpoint.presentation.macroEnabled.12" - ".pptx" = "application/vnd.openxmlformats-officedocument.presentationml.presentation" - ".prf" = "application/pics-rules" - ".prm" = "application/octet-stream" - ".prx" = "application/octet-stream" - ".ps" = "application/postscript" - ".psc1" = "application/PowerShell" - ".psd" = "application/octet-stream" - ".psess" = "application/xml" - ".psm" = "application/octet-stream" - ".psp" = "application/octet-stream" - ".pst" = "application/vnd.ms-outlook" - ".pub" = "application/x-mspublisher" - ".pwz" = "application/vnd.ms-powerpoint" - ".qht" = "text/x-html-insertion" - ".qhtm" = "text/x-html-insertion" - ".qt" = "video/quicktime" - ".qti" = "image/x-quicktime" - ".qtif" = "image/x-quicktime" - ".qtl" = "application/x-quicktimeplayer" - ".qxd" = "application/octet-stream" - ".ra" = "audio/x-pn-realaudio" - ".ram" = "audio/x-pn-realaudio" - ".rar" = "application/x-rar-compressed" - ".ras" = "image/x-cmu-raster" - ".rat" = "application/rat-file" - ".rc" = "text/plain" - ".rc2" = "text/plain" - ".rct" = "text/plain" - ".rdlc" = "application/xml" - ".reg" = "text/plain" - ".resx" = "application/xml" - ".rf" = "image/vnd.rn-realflash" - ".rgb" = "image/x-rgb" - ".rgs" = "text/plain" - ".rm" = "application/vnd.rn-realmedia" - ".rmi" = "audio/mid" - ".rmp" = "application/vnd.rn-rn_music_package" - ".rmvb" = "application/vnd.rn-realmedia-vbr" - ".roff" = "application/x-troff" - ".rpm" = "audio/x-pn-realaudio-plugin" - ".rqy" = "text/x-ms-rqy" - ".rtf" = "application/rtf" - ".rtx" = "text/richtext" - ".rvt" = "application/octet-stream" - ".ruleset" = "application/xml" - ".s" = "text/plain" - ".safariextz" = "application/x-safari-safariextz" - ".scd" = "application/x-msschedule" - ".scr" = "text/plain" - ".sct" = "text/scriptlet" - ".sd2" = "audio/x-sd2" - ".sdp" = "application/sdp" - ".sea" = "application/octet-stream" - ".searchConnector-ms" = "application/windows-search-connector+xml" - ".setpay" = "application/set-payment-initiation" - ".setreg" = "application/set-registration-initiation" - ".settings" = "application/xml" - ".sgimb" = "application/x-sgimb" - ".sgml" = "text/sgml" - ".sh" = "application/x-sh" - ".shar" = "application/x-shar" - ".shtml" = "text/html" - ".sit" = "application/x-stuffit" - ".sitemap" = "application/xml" - ".skin" = "application/xml" - ".skp" = "application/x-koan" - ".sldm" = "application/vnd.ms-powerpoint.slide.macroEnabled.12" - ".sldx" = "application/vnd.openxmlformats-officedocument.presentationml.slide" - ".slk" = "application/vnd.ms-excel" - ".sln" = "text/plain" - ".slupkg-ms" = "application/x-ms-license" - ".smd" = "audio/x-smd" - ".smi" = "application/octet-stream" - ".smx" = "audio/x-smd" - ".smz" = "audio/x-smd" - ".snd" = "audio/basic" - ".snippet" = "application/xml" - ".snp" = "application/octet-stream" - ".sql" = "application/sql" - ".sol" = "text/plain" - ".sor" = "text/plain" - ".spc" = "application/x-pkcs7-certificates" - ".spl" = "application/futuresplash" - ".spx" = "audio/ogg" - ".src" = "application/x-wais-source" - ".srf" = "text/plain" - ".SSISDeploymentManifest" = "text/xml" - ".ssm" = "application/streamingmedia" - ".sst" = "application/vnd.ms-pki.certstore" - ".stl" = "application/vnd.ms-pki.stl" - ".sv4cpio" = "application/x-sv4cpio" - ".sv4crc" = "application/x-sv4crc" - ".svc" = "application/xml" - ".svg" = "image/svg+xml" - ".swf" = "application/x-shockwave-flash" - ".step" = "application/step" - ".stp" = "application/step" - ".t" = "application/x-troff" - ".tar" = "application/x-tar" - ".tcl" = "application/x-tcl" - ".testrunconfig" = "application/xml" - ".testsettings" = "application/xml" - ".tex" = "application/x-tex" - ".texi" = "application/x-texinfo" - ".texinfo" = "application/x-texinfo" - ".tgz" = "application/x-compressed" - ".thmx" = "application/vnd.ms-officetheme" - ".thn" = "application/octet-stream" - ".tif" = "image/tiff" - ".tiff" = "image/tiff" - ".tlh" = "text/plain" - ".tli" = "text/plain" - ".toc" = "application/octet-stream" - ".tr" = "application/x-troff" - ".trm" = "application/x-msterminal" - ".trx" = "application/xml" - ".ts" = "video/vnd.dlna.mpeg-tts" - ".tsv" = "text/tab-separated-values" - ".ttf" = "application/font-sfnt" - ".tts" = "video/vnd.dlna.mpeg-tts" - ".txt" = "text/plain" - ".u32" = "application/octet-stream" - ".uls" = "text/iuls" - ".user" = "text/plain" - ".ustar" = "application/x-ustar" - ".vb" = "text/plain" - ".vbdproj" = "text/plain" - ".vbk" = "video/mpeg" - ".vbproj" = "text/plain" - ".vbs" = "text/vbscript" - ".vcf" = "text/x-vcard" - ".vcproj" = "application/xml" - ".vcs" = "text/plain" - ".vcxproj" = "application/xml" - ".vddproj" = "text/plain" - ".vdp" = "text/plain" - ".vdproj" = "text/plain" - ".vdx" = "application/vnd.ms-visio.viewer" - ".vml" = "text/xml" - ".vscontent" = "application/xml" - ".vsct" = "text/xml" - ".vsd" = "application/vnd.visio" - ".vsi" = "application/ms-vsi" - ".vsix" = "application/vsix" - ".vsixlangpack" = "text/xml" - ".vsixmanifest" = "text/xml" - ".vsmdi" = "application/xml" - ".vspscc" = "text/plain" - ".vss" = "application/vnd.visio" - ".vsscc" = "text/plain" - ".vssettings" = "text/xml" - ".vssscc" = "text/plain" - ".vst" = "application/vnd.visio" - ".vstemplate" = "text/xml" - ".vsto" = "application/x-ms-vsto" - ".vsw" = "application/vnd.visio" - ".vsx" = "application/vnd.visio" - ".vtt" = "text/vtt" - ".vtx" = "application/vnd.visio" - ".wasm" = "application/wasm" - ".wav" = "audio/wav" - ".wave" = "audio/wav" - ".wax" = "audio/x-ms-wax" - ".wbk" = "application/msword" - ".wbmp" = "image/vnd.wap.wbmp" - ".wcm" = "application/vnd.ms-works" - ".wdb" = "application/vnd.ms-works" - ".wdp" = "image/vnd.ms-photo" - ".webarchive" = "application/x-safari-webarchive" - ".webm" = "video/webm" - ".webp" = "image/webp" - ".webtest" = "application/xml" - ".wiq" = "application/xml" - ".wiz" = "application/msword" - ".wks" = "application/vnd.ms-works" - ".WLMP" = "application/wlmoviemaker" - ".wlpginstall" = "application/x-wlpg-detect" - ".wlpginstall3" = "application/x-wlpg3-detect" - ".wm" = "video/x-ms-wm" - ".wma" = "audio/x-ms-wma" - ".wmd" = "application/x-ms-wmd" - ".wmf" = "application/x-msmetafile" - ".wml" = "text/vnd.wap.wml" - ".wmlc" = "application/vnd.wap.wmlc" - ".wmls" = "text/vnd.wap.wmlscript" - ".wmlsc" = "application/vnd.wap.wmlscriptc" - ".wmp" = "video/x-ms-wmp" - ".wmv" = "video/x-ms-wmv" - ".wmx" = "video/x-ms-wmx" - ".wmz" = "application/x-ms-wmz" - ".woff" = "application/font-woff" - ".woff2" = "application/font-woff2" - ".wpl" = "application/vnd.ms-wpl" - ".wps" = "application/vnd.ms-works" - ".wri" = "application/x-mswrite" - ".wrl" = "x-world/x-vrml" - ".wrz" = "x-world/x-vrml" - ".wsc" = "text/scriptlet" - ".wsdl" = "text/xml" - ".wvx" = "video/x-ms-wvx" - ".x" = "application/directx" - ".xaf" = "x-world/x-vrml" - ".xaml" = "application/xaml+xml" - ".xap" = "application/x-silverlight-app" - ".xbap" = "application/x-ms-xbap" - ".xbm" = "image/x-xbitmap" - ".xdr" = "text/plain" - ".xht" = "application/xhtml+xml" - ".xhtml" = "application/xhtml+xml" - ".xla" = "application/vnd.ms-excel" - ".xlam" = "application/vnd.ms-excel.addin.macroEnabled.12" - ".xlc" = "application/vnd.ms-excel" - ".xld" = "application/vnd.ms-excel" - ".xlk" = "application/vnd.ms-excel" - ".xll" = "application/vnd.ms-excel" - ".xlm" = "application/vnd.ms-excel" - ".xls" = "application/vnd.ms-excel" - ".xlsb" = "application/vnd.ms-excel.sheet.binary.macroEnabled.12" - ".xlsm" = "application/vnd.ms-excel.sheet.macroEnabled.12" - ".xlsx" = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" - ".xlt" = "application/vnd.ms-excel" - ".xltm" = "application/vnd.ms-excel.template.macroEnabled.12" - ".xltx" = "application/vnd.openxmlformats-officedocument.spreadsheetml.template" - ".xlw" = "application/vnd.ms-excel" - ".xml" = "text/xml" - ".xmp" = "application/octet-stream" - ".xmta" = "application/xml" - ".xof" = "x-world/x-vrml" - ".XOML" = "text/plain" - ".xpm" = "image/x-xpixmap" - ".xps" = "application/vnd.ms-xpsdocument" - ".xrm-ms" = "text/xml" - ".xsc" = "application/xml" - ".xsd" = "text/xml" - ".xsf" = "text/xml" - ".xsl" = "text/xml" - ".xslt" = "text/xml" - ".xsn" = "application/octet-stream" - ".xss" = "application/xml" - ".xspf" = "application/xspf+xml" - ".xtp" = "application/octet-stream" - ".xwd" = "image/x-xwindowdump" - ".z" = "application/x-compress" - ".zip" = "application/zip" - } + # Thanks to https://github.com/samuelneff/MimeTypeMap/blob/master/MimeTypeMap.cs from which + # MimeTypeMap.json was adapted + $ContentTypeHash = ConvertFrom-Json (Get-Content "$PSScriptRoot\..\config\MimeTypeMap.json" -Raw) + $Extension = [IO.Path]::GetExtension($FileData.FullName) $ContentType = $ContentTypeHash.$Extension } diff --git a/ServiceNow/config/MimeTypeMap.json b/ServiceNow/config/MimeTypeMap.json new file mode 100644 index 0000000000000000000000000000000000000000..38a94f3289bfcaa6ef087a85d39c5c788790ad5b GIT binary patch literal 47128 zcmcJYU2h%9afavGfd50Vw+=;HlCg2_7Ip#{un_|elH3JclA@^95h;=)xeoHzlhiY% zV)Z#y)!joeSgftpboW%($6Fs=)8~Kx=f9R;F27j*?(09_Ew7e0%WL`fyX7C{@4j2^ zmhiZb~#%+Wo~)r$AB?wRoB zO5S%af4*AY$v?dJT>g9`biew_C!XGZr6hYFJA3`KgZq_6);M1Gd@d_xvu>9MdEbc2 z$K^=g{a#i(U4D`oC(FH1btE%C%Aa|XuYDm@>>62AT+sD>bd=A{SIMdFRO=WwZ-iGz z!o5$+f6BZsE8kA#&(}gNJ5YVdXntIGv>S57-n5gok5&mGv5z9H6Oktx_(}eZ=A8;1 zSIa-if1d~^KFTQM{hL)*ai4cG`f>R7TK7MRbZ(#K@8oT_@{j5NjY#Zt`3HG7niAjs zUfzBBG`r$*{q}2lm%eeVQML7=Wm_fiuv!b8JzKT(i>!df+&xPQ@Zo022j~RF?pEtS za_7QnD36>)AI5gJWyRA~vc_jeQ~Uc!1G;@XVU4wJW9jGXj$g?-?CC^y{qwVUd@bAq zJMM;j1|6! z(sZ1vc4?Y;wQ34`bx#@X{C4FzHptqhsTq$yH(J+vO7-n{2z)*WlFh!Cr(=vZ+F4)y zcDB|#p>>Q4ww8^K+JC)b9X?)V+(tcEfO;bQA6ARa#Wn7P&ikhoTwm{G){m=}oePJt zcw!>_*pZAs5pDh=|CL+9kD@o%^3JQLbt_pzWji|3_aM(Tev5lF4iTGNiC++t8!T|MWDY;=&di`m)B&M#D?2xRbcR@wl}N<1eu| zs84J|#Cjo8yOV!%>0eC5)X1H2U}mP3`MyTGR-FeMtNBqci0ZRUqpugl=#FHr3H@1D zGOP79U*z3b$+7%tV;o#xAQ}?#qen zT62<2mv)kYyczD)tO!qtev(|(@lQ)cGbJc)L8GEwokmf^|D;A>rkuJ>^xAC-(Ik&6s z+KO)HeNXuyyc}b4%^xuRa;T$Qye3F^-^i@B6@L~vdM%dcb;(MTwoq~+-pu&PpDl*? zakX=NUMAVIRVRI3ZM8Ns-^;j0vt=)28M9cTBO_Jg3a%okYCrXwDuV~(b2M};wK0*7 zooEQMa2~sC^jRhsa$@(Nm3|nC&E>>qW!d|{4Ue5{gixuZ6c zaR+R4-sJkXMRzXuEX#Mo9*FjcUn`w~>tn0j#&zDNSu_4NuOetnYFudZb$ycO=+rgt zig?MNM4rRrdEK%||4Je~{1%n7x^7Ts<@O}fb0QqFy|>6^f7VKQrhC|kM{6$Y+5>p} zq7i0`*ZwThNWP_&JZij7ZLY8N`#C2X&)=qDwr?Wb!C$AG9D|M4jhYp_A1KnmbZm3L;K&R2v4<3xer%A3HP0Q{@z;WiRg3R zQt1UY;xj6Zc(>-$dgAg<=*o4J6F-f&4|B>sr#^p0SF`nYr$uL2y_xgGUMlFX}F6zDN6jkJ(hlr|Uk3>fq zZRdGgZ2n60o_d9GthIYZJ5YtnfRBtcpNe&PJ!`}RMpv~=<4YekpzLw^?egp8ck(A< z82%TI<}#wUfpe`Jd9R*Gwsn}A-pUfMg&$OS##B-Prv3*1sBK5y-3mA8l^CsNI$K8` zR2<xy)*tUvb1i5|JjZ!f zM$u2}lfLB~uBi2N>QVWsCnCdkpPoyeh)&QmgiYXSB1LcrG+_TD8?3!KoF2;!+?wO` ze7K=!WvB%XaByH~>P{As4Y)R$+h^GNLca$OfM z53Sj1co4FSv9)KuM`uPHAs-mW1jbk5th(nxyKu&KpyR+dbRgR+^45;4ZHOD|8sFNt zM+c50r0Z-yx*-4ZEVzwMc~bRk{`>N$<un}{42qv$_t@M9xFM|`?~&K z=4_v}lT+$1(y{6~;~dqjQ|*NAH|#I+hBNC^k&3O*#&-TJ&LgUt&s*klZR3^pV|iQ_ z-%gdQef$2d>Gsm981-$dndZ?W=sDJ{xw;D3#CWY*bI>?P7~{sMenkzM6D`$O&fexS zD{$)FI*%MbUnO#WClxW*Q|B#x^!g;up{K+nPv6(2=&nAAbFiVGp0silsSxR(2?wad z)8&lc^G^1oz@7L$Y6ISd*IEH~q)+o49%O&rsUTK zYw2jN@4+#m?=``^*H1g2okjN1dXHSIwp4w{Tz$n^IW6>6^;TyP_9s9VLIl+py`1MfR$D+bS9PcN1F2=zm9{{h-vFGHkY|NAmo9{ce(43CN#m zAAMfq{vGhvzV*sh!KOH^%;~XbQOh3J2y?9cYD?Iq&xosO-^sl6)QhzBrdPrzVtdxe z*5@0;Htukp(hM}uGl^Elx?SU!dgy+w1#BimY;($N4@3hOYt@hp)Uyh=*1l(?XLl^G zEogNu)Ql_BrU5z{98ep{>neJN8PCuw?5}yRQH1GrHQ(@{Ux5Q%#(H3D&BQn_+g))d zo``67cDK=fSb>^Ujx}f;+I2N?3cXE($hJLB8c9j%&OH1pS!chd_M9`%op52lTMUkH z&N2H%@b-umTyzc`=9xUDLTxpqh;2K;g0Wp=h1ea^ng1f4p3Zp-hgVeG)sIzQJ)FuI zN3Tla&}$>(p0RqO*^$22=s+*3+e=$XHoT$&qGRIw$%pQnJfof8%azcsG1WFIz86f( zD?;^7@!_?8#e9Lv3Ed+|Ci6p_Q>d-!h`x8L>DtMAyuRXIte#=_D7e(!i`U(k@p+A*xptx=Bv z85Eu4&apfuw{g9y$p_Jv*{-4wD+194WV5(=L%-d~H2PHZ!!^V;u^&%ePvMx2ijpJS z_DV%tH&v|Gr*R%W(Bt(=LMDCl^ko0|@2fSAiK}`KwQ5r9hx}QbN0q~Q7k8mwip6=v zyMD${?P5zTv6GA`&*$g9QrFmLgl6;)w_nKR@eCMAzOPIxuP|9G;pS~qDIP@ z8Uo1ATSj>Y_`wN%)~n#QQqzK@$)iRnP_IB0dh9jfES{q5acTH^1P5w4zhiJTx z%%n+w>e!mi|9nfGt?CJ~N}F}JX1pg~^(tHCUuH3on{u4*)oNI_jf|Xo&S^%QeL2?l zvPYMs~QsKsor z8TdKr%Tx-;4IR}EsaHPRn8;^3RL9y$hZNY;ufIET_A$}NMS95gyuLLnLCti{-?TjF z<-nh1?=O4KL=WB=k+$G0_Z@k3+Q!1@=3G2U9zCXN+>xwZePmMY$!3K?;~qfnkaW$h z*U>K{X6|aEKGsINnSVT%F+|RKi zs9li@koObA5*^vykiU|MfjB*rBwlvr&IY6G|1V|$*}$e=-{lX>AC`Y@xahf?(dQKv zc&L^9h^f5E>zply*poQtLHIfL3r2@|8BYAGUVqLi-8bj*Jr+8t51^U&8|4o%eI`vh zAloR^y#>1NPvh>uRPE?gPu23opT&7Zaxd#K9%QF}b_(5kMoMgJ-}BQE0_P$<)RJ7X zHBaeD1VynLq#9RJ-i<64`fOxegDfNK5%iOcI7hw2=)GfKLdP_nUiz3Pn5$p z_l@k1^Cfnuwe3hRy&7*C9f;Vy->q@{kDbKmEGEdL_i{C|4VF~^^NmV!NG zcA{B58pVlK&uT7Zj7NnPU$9m@A!luTrI_vCsu1Iy{8}K&DviYG1i|& zyCAC?Q)4n$&*M2&wnsg+9NU`mYrk$sewQOAoo*iE%*%e}?0}A%Pa-!R8+oMXnueMY zgE+0x?``wWaynn#Z*28C+PUfTTkq-5BGn(o)8Wbc+2NM#h@RB(itNuuMyfQ!%6G%e z*@$;0^Fyj=3P^>YA$A3OvbX{(1wj#>g|oV}ZKFIN74kx{0XZppd^ z9b@gNoC=TOS}N+UH8MD-yy6{v>-EfG$4+^*3j5%U>!Y9ox<|G0LhJ_p(>a-*QR^n& zeNMHII?-6yjKB2DF}`;)3eEU%Mq(v!#w1qlTTv8F^QG+3x^G{jcgBmyn89gwaCp*V zGozm1*K?e)Cvnajkrb9{du=VlpT&8q`!=i9N#*+3GQh=gzQ$@1AvON_dDXT|x4`&u zMQV#D;4WY94?5hhJ&k;#cGBjMl`hq1fI?d+v6i0UWL&`pX1=?rX~A=h>tAMf z>WOxu!Q2a-XP6qPWqQ<$;lPedkuZ@QJ-t?;v2|LEt#Vs#FtqWl)26z7za^p9#O^^=9d^WtBcdd*KBvoNiZ8_iX1_>hog8Uc2^oD^*J2bD<~28} z6W%x2;*~z>;mWn3i04`rHtcHxr#>^^;n7{C8Is|Czfw`hVRnn`{;&HycQuQqT!K~Z zu2ENpfckrHqZPL3Cb{9*y0@%|#kQw1m2~~a1D_FfUb_WHJGNL@vqU<3schqY;))*Q zxb^j;BfbGP3TEd}sd5zYS@!plE)c+TpNeZ+B%vLaM2uCBzj>&`k&!yG$nB95@vU+0 zF#0!qXGDCTR?+j>{w&V>>+;v-kMi#y1h z(`QuD(NX>Ga3Uth&1xlNR%x*RhKk+__FP0lI{CdBhP-?Qp}*#&Bm130jGpP-@NrRo zpky1lR2YdT)!%jiE%W*~8O=-O^k~eOu3CS{+FY9}sc*4vGWVCo3)MNZikF~KGZ!$= zR&C=1dpeib@SAck>!~;et|KaHZ`zxG`*mE@Rxq9~a9R&h@eLofKR&Jpr--(ncall$ zI_3~`#1jmx=t9s@Yv_?O(0ZKnY|&qSXVG&@$Kbv%*8Z5^3oVDg>f|fbR!IEhUir`? z+0(dtDoosIZCY&EQ~&qE=I&lFtW|%gb7pEzbU?XB^4<6ON1v!?6$fEbW;aA(6l{pC| z&&lY;SGx~7)LyEzoCMYVhRkq_YmwM)ipbt-(fR8}`*W`xBYNgUzUzsHuh;IxPDApU z#5>M`R(sWl*xzJtMf3e6#70uZLI&9ky$4l)XV)y>=k@LETySQ5s){z;i@X^b`9xIi zw%W>z`}C-F+K6l}zTkO&gzp`1hSK)0A{k93#%_j-)DRW6`Tl)VQFoU2 z+=w-fwe0I$Zo}gAge)PWf%A`RVHIPTpV><--P6`vo6YO)`CECAFBj?rE%be8R)3u7&JeXGQK2 zC(N8W+PHq5d!|2V-*e2?xrtpp{;%|8e{FuHo=RT*-9Fvl?is38w_ppm+P&;|H{?j} z-&?do$~>iO0SV)8qJ+uwJighgZ(4nHPu9NQpT)PT@9^lg;;l*STe1!FI2r+FT@8nx zDC3h=(HT3VYqj^)*xR*L5&LfaHlm8YIguQDg)N%sXWoW2l?;4j&$`JEMk|@OCSvLR za)R@wrm01+OkVh>Hw{G|W%oRnb_f2ZnU`mGe-YF`zi*_vPCUz(TNxGf%D8n^yV)W) zI<%?el0j4d`BrV@7j4FpGdt9HUM;FRhlamzpE!6JGw>wh0TqolC(5}FIvE8zKCZ;6 z!Sw)LyhQ_u*TxcKhubTg9uILYh!EeCSU)e(~uYJuD|T$M&;+0AZ>dZ zxk8>Z&YEmbbKi?r_RNrjBN#Z=bmNtd29vT~Q4egZ&|@8=s*Xw~0SH4Zw;vQzsqQGF&c0QbD>sYJGxe#idTMjoyw#OnDO3tG2-`*s!QRCxfm zTkl8DhI9E!+kSnG7@nG=@u-rfkBim^rnIP*)3ps#Oi$>B<%~MM^?pUN{pi3Y-1nn& z4!FfTW@}F`6^Q*i|3`PmQbn>~dLgR0n}`|E!FJyMfB7nL=iCV}=C|s&j*M$))r)Lm zBze$tR3qCzBdT<0OO%A&?B9f#YgLV%R(0pCqdktR?(JE9t1qV2`(JHqET&&|M&5Jx z75noTs^SnX1LLA0W(V_(ZUb@i6tdKz=dV!6y3xx;KuCv9Y;Uw?2r*BzSP=JcHQgk;oUYS@=|XPv0b$K-n&5XMTVJ$7#2MU-e!~l!$#;loXYXs8$D(VD zGo=3SKWjgqAxXtC8x^?&Dz-S5M*&+f#lAy`vQY`R1=r|GzfkLMT3z*LaW@*X8aMn+ z{b-e5F1L%;mfVlnnD|a=9PXJ9^{e^@Rr#)cE!u5JjtSBc8_#*U!!Os{HMItd_V}v3 zvj**pGS0QTu#Tw=UGYfX?^tPHEoZcCi~kv&ytQ8h&PpHLe%tJ#-Mc=^cFu28wV3F+ zs_KkBjoQKuyN=tfUNeuUAPsR7IWN-% zPgT>k!R2RvA9umIgvSPl-2AY5{y2+xGK=>5D8ZS7zssq!zmM;+%1MhYIljW@c63~e zdE2|hva|lI8}vDSLQu55S1G5cs&GDsu5-~>ms5pF`w^&hmU3U_hmNP#nwFuY>wwj| zGNhn-Gvi@(RFwRK&@}FE80AoW6*RW@EqsQ%qT+e5L!R;3+ zj=}aMa&zY93)7ALnuCA$pGleC#5xMVwvXiBs&`uJBbwowc2$}?uBCtzE}43r`8<(K z*1e6(+Bmh}4WIFcyY;^1%agWJ@9*#H8sFa-H)rRNr+B_NJB#z9Uq8L8;<#l;IyUMi zzmzcc74`2akY%`(Dk^MLe81l$Vz%iP<>L>PYa%66&&UWmas@_T7g|&iWjE=NlN{sB^ zNZ4ET3_|M%HX_cYn`#_IY}J7umLHbiH#p(iU7v6%_EPN{X{1SEAC22O8EeG763LAt z6kA<6m&I|}+Gy5@Zq}mzucb6w>r|q4_pvU|z6R?lfgxHQe^;jomc7nbFNi)oD{k{i z^u?Y=Ip8DRW3}_h0;|q&@^kN9XlGgG&eQldk690Q=1<}*P!Q=g@Qh(tSrW`PnwkaI4}>uRS(7Iz!akMn<-{g+9GW)K;9eN5-kO6Nzwc z!Ch!GXLTBbMpRW7V78IY6zZ{jHsN8!VXWdGVRmf7q*>{0duOJ O|F-ZimtQRZz5E}3#cIC* literal 0 HcmV?d00001 From 44e8b716463b960fa74273491676074725cd58f8 Mon Sep 17 00:00:00 2001 From: Nate Scherer <376408+natescherer@users.noreply.github.com> Date: Fri, 30 Apr 2021 09:00:43 -0400 Subject: [PATCH 215/348] Switch encoding to UTF-8 --- ServiceNow/config/MimeTypeMap.json | Bin 47128 -> 22929 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ServiceNow/config/MimeTypeMap.json b/ServiceNow/config/MimeTypeMap.json index 38a94f3289bfcaa6ef087a85d39c5c788790ad5b..ca56e358d95650104b998219bb0a4fbe3cd01f76 100644 GIT binary patch literal 22929 zcmb_kOONC@a=!1cSnPGJ>gldFdhOd_*9HdIffpFV_HDtGlqpr|!4j29%^3dg{vs$+ zK?PM^Fx;0ekrWk-_lx=8zxzG@{o(2P%kv-p`S*XA>vjIr(8E7$6AxE)ac1qiI8n71 z8gF}Zt3O?O8z)}M-)O>E+qI>c+j02RwQu*f>PLEr>&A6Hu3LucX|(k)UaxIgkJIf5 z@YI8oul4o|y|%PfJ$~wKeTy5q$Mv}3TDWE`Ums?vi)&|GvoF52Js&{AiRC;T4nN^o zhocaP(@;#q-}}33%fDMwz5)Yr-?cM+?w#Hh^;*{5lc}n9cWGwm)2Zqj5c9;S7L z8}C!O^H#Ig$1h3dm`Alw7OP{WxPS%ExYn`wMLIhRvQ>=Cc$7CrnHN7ub@@8C{SM+X zEB>XumliS{x42e{{IrOM1H$Yu-{`Dfy{rY~#R6wL)@Qdwbk62dxZ0Y@%ym^Prn}cW z>My0mrw>xR7JfKCDved?FO(>W1Uzvt+qH zvtpC_D7&uzA}BzhR^4EpND~(Gyr27~wD4NoertCcFi8x&1``LJfG;;0MWj-Pc$3AD=qJs0ivpzzk6$FR^mWymrL7-vVds@t z=4kE)HVit49|EF!r2*Dro?v$Ig}CvfuW}F+G#)mBW#u(YTzUu-<)nxPYC(TuJghN} zm4(+Op6A@I0{YLqb;i)o%F1le$DLPiIL>GQx8!&-$x(Gl3j&l&l~rkAKh|o{ZS|v` z;__Z=KuP|7QA!#oZx_RsrG+~XcY>8WfimS3S28{_4De_b*GgELwLN|y%hXl72tx5w zK#sjCL!8~h+;=v)z|fTOl+~huSPL55KcSqG>?dZEV+#z1jWP<6tobAj^`jR|$1F)B zVTZo0Jh05}c#1P)mF1{W+f*V`d~GRrwX_yXX{LS4heWyu1tSp@r_h$gO6v*4%u$-I z9x8#6u~O6{Imkd=85mjPc0&&xNfh<=84vrJTr&%`!w&&yYqMA)O+G?~>?kdKVv=Qm zVT3&~pagvAh?Z(*oyEtMtj>V~;LT_gH^4iq6=3r1aaPkOc%ly%(H#iqcCC6Jp~iei zm?Q9((G0?ka5a2rWmzyZMM~c4p`IZA zbtaS&+-v)X-q6<5wHFxy*Huc@6GjvL@Z>s#{-;45_@6$MVa9dp$-4=YlHXeIx=Tu~ zMLXYz+Tp)lyR^gZPoBu)v0puW-SpYkIcjC?vq~I4xdwg zktC+moG1=P%YY@{8&?N;wgvpI76vV#>ET!%Fz5NH4pt@1l7LM2 z;rsEyi~k;P^K$qE>}S>&rJNa1a2==K%&ze1vlzvbhXZxNMxpPXA5QF9uh!LSLF*}y|x>1eQ7Q`4#9;vZACjM^&EEqlO-7$ z(|Vi9E-N1P0Bh3Ll!gKcN2dcHVl-Eqscfp+^CnWWf0WYK8&*6S{o9-d=l%2jPmF7Z z5yl9)jJu2zmy(sb*Jg&EB9M8Dk?~*&BBYU6TZOl$jkmV%TI6+W(~(cPYrj!rN&6hl zsvHxEl*#)}8KgYw3t_WebY`z`=4z(45K98w{a0_o8E$$A6L%jn@`qY_2ouJ>9=Vz1 z(G1lzw$;;?#V!IY;kCA8BN4K2c-+&LNW>@Joyf$mol+B<3Qi-})vHXYTP50BFP+JB zG|QL^P&S)^5)}uzO}~0<$?2k}(XfFjpLhPFhcI!oO5b8AVR-vZSuU8j*V27sN2x_6 z1DU~{5=|{5Cw>ZF>rWBtx-9u%9#e$EuXg2bhEgA8D!)X1lFryk`CVD>#kk#lPIstv zYMLqDqRipO>-=QL2@zyh1K_&6^PdsR#(m6rf~8jEkc75YIR+cs?WQ7rw0{-c3!P(- z|8lP;&Nq$Xnk-JnRezPoB2~W%_o>H2m{=~mH;TVgZ{np?6wg-C+{U4-3S@Q_*&~H4 z!p8f)g2?#8RY)`cNIPB`;-H7yE7I<7_j(XDibt!`EWM-ZQ9QP>0~_6K7kUa9Sufst zq!JG<=ZUZiX^ia2u+DovPrM>7ueJgWqbRX}&8m^Yn7> z9dUW0EF0N-Mve3i!(9t9>^_(boaL?(aHxSJO@s- zyHN$VdCZJHXqSgoV*M2Stkb}-4{52B;^~>zTraHif(cwN?MyyS;I96v)WmtwxnHtG z);axBSICe$7xl5VpOxz@IpE=`5wZXjM`0uaZ5K8L8NavD`_fQ&b8*6zksq`}f~KhM z&G4&47cyb><|0aZ%ANXweGc|vK3u8^_nUlGDIIj+d1*DZFV1*1_0cl#q}jKPs!N9_ZhM z!Pb>$D3^n>jwP)fKR55dgk#cUI40ce?5B8wyx~DzLS6qx96wRz6-OySs z*SpWV3*t9rX4m4|Z(Ky8f`%v~*JK(2HnkOR`L z?TQqd1*u$WtT>WUV246ql~{64gVjFXKC=(MX}T392IB!c9WRrh zyzg+yYz%o^l-!J4*4nkqaNJyG5^OXWAUll+ygAB*rPCYRX3xFIniez=wp)GnA@kaJ z+8*%JfBY-aHQ1we*;Nk;;z|o{3WkH5@0<3AZ{7%-v$5M5%dARlN0jzcFOFI9z<3FJ zBI!d1$Q&Bkiv4I@X9|dV`(RSomWs8q4Ei>UG{{ z2}}{1>k9Lz<&|ii*+v>1z0Z^hQD`G-c|~fJMY>ondpKIXSJ3*efBX5bgsY6!Y$~j|_SUSbDzsI*_LTKZPlv{9OvX=|)h&elS+QiagnFiJ97&n98d()XTb499}pfi?}|xc%p^N2;(IP>r*_Wj!Wg+4KsVx#P`_v0}xT z0cq9OM6#?#`j{<E73q;TUTaPfGeB2LQ`{G zm*nAP8h&m**0GMpchy6}dXXmrIK7wm44SDGM*2%;EAK>SckAwZqKUAb(Ft`WbdUG$ zv50PxvQd#|mT;}}ZK3iE`Gv8?G6-TE2=Gtd+2AuG50fi7PeyPFjBkH0Fhp%OVH39q zX9f=mbJ&N<4Q+g#DT9?GYz$psIvNcjQPljoT}63k73rblE<6^1#s#e7d=`n;sZ3FJ z-2>I0hRx>gOzAwBb$2%r3H}HI9BMJkPhrDfe);K_zi{z|S_pqOLwns?_dF1S z?C2;x9t1;a!nt~=`o45k^H$5wonGRR}$WJ|u@nHIhJ zkC^OQ?<7sOxqeJ*yx5O10uXk@bCzLXFG`^p=uw-G>Vv}5qts1Yy6GWR{-(M|?q1q9 z9*|x-@&(RrwzV1b?c zd-stYV?(CDGsXQ)mtrP#*u{NjkzYvrBUYaTQ9#|1Qp#k`{cr#e<=oR0E~H0QnuHMT z9eHSu(CV2|1n)X~GFuSR)3{PAZy)ilK@WANNYZs^86YL)OEBN_C(`IkI!*4^-lg zCJn?%@hPbJexZTr#adHfAgiNplI`gsfIxTbjyoJLul2f_kcPq*z^aaaD9wpm z)qC4w@A=eAO_JxhWi<|uhEMdDQRxaEiwpF{A#z`kkdv3GT&`RAoz}Q@WZazOwtAzY zl33xzQ~+&tI;^9y)J4`AnN1EdF0wssC_fg!n@p)GcmKUZCBY$ zaqZZ2oZt&?AN$e%ZGH+kf*>gR()r)F1uF1Y)e3T`zgI+uS{6R9a5s(5Y)bzwkCf2J zBUkDW`9moE52OcyYU`Ar_c(N4{=#=X&c=0{Dp2?ED z)U+t1cyivHS}lem<@!Y0%gY_xV~IzG+jFXj5Ztsedk^ND=b8k5=cp+WGxJrFUm zNR{zZpaPO8N4yZJ5An>GkM$#=>-N2_6ml{|G$4JBQD@s&Rp^_o%ma~$%1xX%H-;X= z$t?P^=xYfNl3ft}TBA<$oP1WgsPPl6)fZ6qL^VwYV2opC4-PD{`qF`&yaoQ7V|^B{cL){2!FJs2;+PSDG6)BZ(yJ zv7KIwL^1l8olOilcSoXbl$XBQ6%hiA+Ogjh?lWO4{m=rb1Mh^1UtK6Yk9%&SMEPDOu-`I1%pQA8 z^&9oKM4}1{nBBpSh46;lX0sx)Z4ACi~8HOg0eIjNRnWBQ*lqP+HUrEy?4_UGCexxYXR6Yt0XcCo2e}@ps zx`8j4W<)Dgq5VpDp4-wSj6-gS0P`P6O395!X+lbISeph`QBn>8mM^4b&JFikkWBuv zLI2hBU664+1~je@kvhV4dVj>~j-*Fe;@(uTf`;PstKx;VcpXLbOGZT1a+DFNypPNW zqrb!c^eY9xXOO3t{br8qc9oX0z#{T`OKK!qO;i;$E&^Vau3+&9Hi*75Xm z2QEf`U?1rzo^Dm2rUocEIbM>AB|_0C8AT48Uwc;T_sM`{R{XcYerrPk30*0dj<9P%GqscXI*DKFAdt9Wu zBf<%wtyUDlUM}xBc&+!ra{|4$PNeL;{pL#M75n*z6egk9@X?Xk=NJGeq z$H-r+;n8r?vl8bxE5GN&!=NwHMd|oeg?N8uVfPQ(V~0Bp1b|Af2NTK3|NP01KmK_~ zvW$qRs;ST{IM(}9djy5wIXGgQR>LRT6=8(WC}GK53n=}MY-Tt&*Wo7`{K#bm-|>sm zeeI>qgR#eBK-l8-nK#6V*ZzF_LYwU-davGuJRW~2(Vo5TB**)~v%8`FF%lrvMwDFr$OX`?P|TQBkx=D-FD~V7b)~0y zQ>aB$t~4;8n^Okm<$tQhzk}(pCl0!CL(X?`(cm@__LAw=G<>xhM#s5 sH=))}T?E=>ERB26?xTb;OQ^9@hV4W_g%BvhjO(aGiZb~#%+Wo~)r$AB?wRoB zO5S%af4*AY$v?dJT>g9`biew_C!XGZr6hYFJA3`KgZq_6);M1Gd@d_xvu>9MdEbc2 z$K^=g{a#i(U4D`oC(FH1btE%C%Aa|XuYDm@>>62AT+sD>bd=A{SIMdFRO=WwZ-iGz z!o5$+f6BZsE8kA#&(}gNJ5YVdXntIGv>S57-n5gok5&mGv5z9H6Oktx_(}eZ=A8;1 zSIa-if1d~^KFTQM{hL)*ai4cG`f>R7TK7MRbZ(#K@8oT_@{j5NjY#Zt`3HG7niAjs zUfzBBG`r$*{q}2lm%eeVQML7=Wm_fiuv!b8JzKT(i>!df+&xPQ@Zo022j~RF?pEtS za_7QnD36>)AI5gJWyRA~vc_jeQ~Uc!1G;@XVU4wJW9jGXj$g?-?CC^y{qwVUd@bAq zJMM;j1|6! z(sZ1vc4?Y;wQ34`bx#@X{C4FzHptqhsTq$yH(J+vO7-n{2z)*WlFh!Cr(=vZ+F4)y zcDB|#p>>Q4ww8^K+JC)b9X?)V+(tcEfO;bQA6ARa#Wn7P&ikhoTwm{G){m=}oePJt zcw!>_*pZAs5pDh=|CL+9kD@o%^3JQLbt_pzWji|3_aM(Tev5lF4iTGNiC++t8!T|MWDY;=&di`m)B&M#D?2xRbcR@wl}N<1eu| zs84J|#Cjo8yOV!%>0eC5)X1H2U}mP3`MyTGR-FeMtNBqci0ZRUqpugl=#FHr3H@1D zGOP79U*z3b$+7%tV;o#xAQ}?#qen zT62<2mv)kYyczD)tO!qtev(|(@lQ)cGbJc)L8GEwokmf^|D;A>rkuJ>^xAC-(Ik&6s z+KO)HeNXuyyc}b4%^xuRa;T$Qye3F^-^i@B6@L~vdM%dcb;(MTwoq~+-pu&PpDl*? zakX=NUMAVIRVRI3ZM8Ns-^;j0vt=)28M9cTBO_Jg3a%okYCrXwDuV~(b2M};wK0*7 zooEQMa2~sC^jRhsa$@(Nm3|nC&E>>qW!d|{4Ue5{gixuZ6c zaR+R4-sJkXMRzXuEX#Mo9*FjcUn`w~>tn0j#&zDNSu_4NuOetnYFudZb$ycO=+rgt zig?MNM4rRrdEK%||4Je~{1%n7x^7Ts<@O}fb0QqFy|>6^f7VKQrhC|kM{6$Y+5>p} zq7i0`*ZwThNWP_&JZij7ZLY8N`#C2X&)=qDwr?Wb!C$AG9D|M4jhYp_A1KnmbZm3L;K&R2v4<3xer%A3HP0Q{@z;WiRg3R zQt1UY;xj6Zc(>-$dgAg<=*o4J6F-f&4|B>sr#^p0SF`nYr$uL2y_xgGUMlFX}F6zDN6jkJ(hlr|Uk3>fq zZRdGgZ2n60o_d9GthIYZJ5YtnfRBtcpNe&PJ!`}RMpv~=<4YekpzLw^?egp8ck(A< z82%TI<}#wUfpe`Jd9R*Gwsn}A-pUfMg&$OS##B-Prv3*1sBK5y-3mA8l^CsNI$K8` zR2<xy)*tUvb1i5|JjZ!f zM$u2}lfLB~uBi2N>QVWsCnCdkpPoyeh)&QmgiYXSB1LcrG+_TD8?3!KoF2;!+?wO` ze7K=!WvB%XaByH~>P{As4Y)R$+h^GNLca$OfM z53Sj1co4FSv9)KuM`uPHAs-mW1jbk5th(nxyKu&KpyR+dbRgR+^45;4ZHOD|8sFNt zM+c50r0Z-yx*-4ZEVzwMc~bRk{`>N$<un}{42qv$_t@M9xFM|`?~&K z=4_v}lT+$1(y{6~;~dqjQ|*NAH|#I+hBNC^k&3O*#&-TJ&LgUt&s*klZR3^pV|iQ_ z-%gdQef$2d>Gsm981-$dndZ?W=sDJ{xw;D3#CWY*bI>?P7~{sMenkzM6D`$O&fexS zD{$)FI*%MbUnO#WClxW*Q|B#x^!g;up{K+nPv6(2=&nAAbFiVGp0silsSxR(2?wad z)8&lc^G^1oz@7L$Y6ISd*IEH~q)+o49%O&rsUTK zYw2jN@4+#m?=``^*H1g2okjN1dXHSIwp4w{Tz$n^IW6>6^;TyP_9s9VLIl+py`1MfR$D+bS9PcN1F2=zm9{{h-vFGHkY|NAmo9{ce(43CN#m zAAMfq{vGhvzV*sh!KOH^%;~XbQOh3J2y?9cYD?Iq&xosO-^sl6)QhzBrdPrzVtdxe z*5@0;Htukp(hM}uGl^Elx?SU!dgy+w1#BimY;($N4@3hOYt@hp)Uyh=*1l(?XLl^G zEogNu)Ql_BrU5z{98ep{>neJN8PCuw?5}yRQH1GrHQ(@{Ux5Q%#(H3D&BQn_+g))d zo``67cDK=fSb>^Ujx}f;+I2N?3cXE($hJLB8c9j%&OH1pS!chd_M9`%op52lTMUkH z&N2H%@b-umTyzc`=9xUDLTxpqh;2K;g0Wp=h1ea^ng1f4p3Zp-hgVeG)sIzQJ)FuI zN3Tla&}$>(p0RqO*^$22=s+*3+e=$XHoT$&qGRIw$%pQnJfof8%azcsG1WFIz86f( zD?;^7@!_?8#e9Lv3Ed+|Ci6p_Q>d-!h`x8L>DtMAyuRXIte#=_D7e(!i`U(k@p+A*xptx=Bv z85Eu4&apfuw{g9y$p_Jv*{-4wD+194WV5(=L%-d~H2PHZ!!^V;u^&%ePvMx2ijpJS z_DV%tH&v|Gr*R%W(Bt(=LMDCl^ko0|@2fSAiK}`KwQ5r9hx}QbN0q~Q7k8mwip6=v zyMD${?P5zTv6GA`&*$g9QrFmLgl6;)w_nKR@eCMAzOPIxuP|9G;pS~qDIP@ z8Uo1ATSj>Y_`wN%)~n#QQqzK@$)iRnP_IB0dh9jfES{q5acTH^1P5w4zhiJTx z%%n+w>e!mi|9nfGt?CJ~N}F}JX1pg~^(tHCUuH3on{u4*)oNI_jf|Xo&S^%QeL2?l zvPYMs~QsKsor z8TdKr%Tx-;4IR}EsaHPRn8;^3RL9y$hZNY;ufIET_A$}NMS95gyuLLnLCti{-?TjF z<-nh1?=O4KL=WB=k+$G0_Z@k3+Q!1@=3G2U9zCXN+>xwZePmMY$!3K?;~qfnkaW$h z*U>K{X6|aEKGsINnSVT%F+|RKi zs9li@koObA5*^vykiU|MfjB*rBwlvr&IY6G|1V|$*}$e=-{lX>AC`Y@xahf?(dQKv zc&L^9h^f5E>zply*poQtLHIfL3r2@|8BYAGUVqLi-8bj*Jr+8t51^U&8|4o%eI`vh zAloR^y#>1NPvh>uRPE?gPu23opT&7Zaxd#K9%QF}b_(5kMoMgJ-}BQE0_P$<)RJ7X zHBaeD1VynLq#9RJ-i<64`fOxegDfNK5%iOcI7hw2=)GfKLdP_nUiz3Pn5$p z_l@k1^Cfnuwe3hRy&7*C9f;Vy->q@{kDbKmEGEdL_i{C|4VF~^^NmV!NG zcA{B58pVlK&uT7Zj7NnPU$9m@A!luTrI_vCsu1Iy{8}K&DviYG1i|& zyCAC?Q)4n$&*M2&wnsg+9NU`mYrk$sewQOAoo*iE%*%e}?0}A%Pa-!R8+oMXnueMY zgE+0x?``wWaynn#Z*28C+PUfTTkq-5BGn(o)8Wbc+2NM#h@RB(itNuuMyfQ!%6G%e z*@$;0^Fyj=3P^>YA$A3OvbX{(1wj#>g|oV}ZKFIN74kx{0XZppd^ z9b@gNoC=TOS}N+UH8MD-yy6{v>-EfG$4+^*3j5%U>!Y9ox<|G0LhJ_p(>a-*QR^n& zeNMHII?-6yjKB2DF}`;)3eEU%Mq(v!#w1qlTTv8F^QG+3x^G{jcgBmyn89gwaCp*V zGozm1*K?e)Cvnajkrb9{du=VlpT&8q`!=i9N#*+3GQh=gzQ$@1AvON_dDXT|x4`&u zMQV#D;4WY94?5hhJ&k;#cGBjMl`hq1fI?d+v6i0UWL&`pX1=?rX~A=h>tAMf z>WOxu!Q2a-XP6qPWqQ<$;lPedkuZ@QJ-t?;v2|LEt#Vs#FtqWl)26z7za^p9#O^^=9d^WtBcdd*KBvoNiZ8_iX1_>hog8Uc2^oD^*J2bD<~28} z6W%x2;*~z>;mWn3i04`rHtcHxr#>^^;n7{C8Is|Czfw`hVRnn`{;&HycQuQqT!K~Z zu2ENpfckrHqZPL3Cb{9*y0@%|#kQw1m2~~a1D_FfUb_WHJGNL@vqU<3schqY;))*Q zxb^j;BfbGP3TEd}sd5zYS@!plE)c+TpNeZ+B%vLaM2uCBzj>&`k&!yG$nB95@vU+0 zF#0!qXGDCTR?+j>{w&V>>+;v-kMi#y1h z(`QuD(NX>Ga3Uth&1xlNR%x*RhKk+__FP0lI{CdBhP-?Qp}*#&Bm130jGpP-@NrRo zpky1lR2YdT)!%jiE%W*~8O=-O^k~eOu3CS{+FY9}sc*4vGWVCo3)MNZikF~KGZ!$= zR&C=1dpeib@SAck>!~;et|KaHZ`zxG`*mE@Rxq9~a9R&h@eLofKR&Jpr--(ncall$ zI_3~`#1jmx=t9s@Yv_?O(0ZKnY|&qSXVG&@$Kbv%*8Z5^3oVDg>f|fbR!IEhUir`? z+0(dtDoosIZCY&EQ~&qE=I&lFtW|%gb7pEzbU?XB^4<6ON1v!?6$fEbW;aA(6l{pC| z&&lY;SGx~7)LyEzoCMYVhRkq_YmwM)ipbt-(fR8}`*W`xBYNgUzUzsHuh;IxPDApU z#5>M`R(sWl*xzJtMf3e6#70uZLI&9ky$4l)XV)y>=k@LETySQ5s){z;i@X^b`9xIi zw%W>z`}C-F+K6l}zTkO&gzp`1hSK)0A{k93#%_j-)DRW6`Tl)VQFoU2 z+=w-fwe0I$Zo}gAge)PWf%A`RVHIPTpV><--P6`vo6YO)`CECAFBj?rE%be8R)3u7&JeXGQK2 zC(N8W+PHq5d!|2V-*e2?xrtpp{;%|8e{FuHo=RT*-9Fvl?is38w_ppm+P&;|H{?j} z-&?do$~>iO0SV)8qJ+uwJighgZ(4nHPu9NQpT)PT@9^lg;;l*STe1!FI2r+FT@8nx zDC3h=(HT3VYqj^)*xR*L5&LfaHlm8YIguQDg)N%sXWoW2l?;4j&$`JEMk|@OCSvLR za)R@wrm01+OkVh>Hw{G|W%oRnb_f2ZnU`mGe-YF`zi*_vPCUz(TNxGf%D8n^yV)W) zI<%?el0j4d`BrV@7j4FpGdt9HUM;FRhlamzpE!6JGw>wh0TqolC(5}FIvE8zKCZ;6 z!Sw)LyhQ_u*TxcKhubTg9uILYh!EeCSU)e(~uYJuD|T$M&;+0AZ>dZ zxk8>Z&YEmbbKi?r_RNrjBN#Z=bmNtd29vT~Q4egZ&|@8=s*Xw~0SH4Zw;vQzsqQGF&c0QbD>sYJGxe#idTMjoyw#OnDO3tG2-`*s!QRCxfm zTkl8DhI9E!+kSnG7@nG=@u-rfkBim^rnIP*)3ps#Oi$>B<%~MM^?pUN{pi3Y-1nn& z4!FfTW@}F`6^Q*i|3`PmQbn>~dLgR0n}`|E!FJyMfB7nL=iCV}=C|s&j*M$))r)Lm zBze$tR3qCzBdT<0OO%A&?B9f#YgLV%R(0pCqdktR?(JE9t1qV2`(JHqET&&|M&5Jx z75noTs^SnX1LLA0W(V_(ZUb@i6tdKz=dV!6y3xx;KuCv9Y;Uw?2r*BzSP=JcHQgk;oUYS@=|XPv0b$K-n&5XMTVJ$7#2MU-e!~l!$#;loXYXs8$D(VD zGo=3SKWjgqAxXtC8x^?&Dz-S5M*&+f#lAy`vQY`R1=r|GzfkLMT3z*LaW@*X8aMn+ z{b-e5F1L%;mfVlnnD|a=9PXJ9^{e^@Rr#)cE!u5JjtSBc8_#*U!!Os{HMItd_V}v3 zvj**pGS0QTu#Tw=UGYfX?^tPHEoZcCi~kv&ytQ8h&PpHLe%tJ#-Mc=^cFu28wV3F+ zs_KkBjoQKuyN=tfUNeuUAPsR7IWN-% zPgT>k!R2RvA9umIgvSPl-2AY5{y2+xGK=>5D8ZS7zssq!zmM;+%1MhYIljW@c63~e zdE2|hva|lI8}vDSLQu55S1G5cs&GDsu5-~>ms5pF`w^&hmU3U_hmNP#nwFuY>wwj| zGNhn-Gvi@(RFwRK&@}FE80AoW6*RW@EqsQ%qT+e5L!R;3+ zj=}aMa&zY93)7ALnuCA$pGleC#5xMVwvXiBs&`uJBbwowc2$}?uBCtzE}43r`8<(K z*1e6(+Bmh}4WIFcyY;^1%agWJ@9*#H8sFa-H)rRNr+B_NJB#z9Uq8L8;<#l;IyUMi zzmzcc74`2akY%`(Dk^MLe81l$Vz%iP<>L>PYa%66&&UWmas@_T7g|&iWjE=NlN{sB^ zNZ4ET3_|M%HX_cYn`#_IY}J7umLHbiH#p(iU7v6%_EPN{X{1SEAC22O8EeG763LAt z6kA<6m&I|}+Gy5@Zq}mzucb6w>r|q4_pvU|z6R?lfgxHQe^;jomc7nbFNi)oD{k{i z^u?Y=Ip8DRW3}_h0;|q&@^kN9XlGgG&eQldk690Q=1<}*P!Q=g@Qh(tSrW`PnwkaI4}>uRS(7Iz!akMn<-{g+9GW)K;9eN5-kO6Nzwc z!Ch!GXLTBbMpRW7V78IY6zZ{jHsN8!VXWdGVRmf7q*>{0duOJ O|F-ZimtQRZz5E}3#cIC* From df69f212e93a405b83178d9d6173847650a9f1fa Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 13 May 2021 23:03:35 -0400 Subject: [PATCH 216/348] add paging support, pipeline enhancements --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 177 ++++++++++-------- .../Public/Get-ServiceNowChangeRequest.ps1 | 4 - .../Get-ServiceNowConfigurationItem.ps1 | 4 - ServiceNow/Public/Get-ServiceNowIncident.ps1 | 4 - ServiceNow/Public/Get-ServiceNowRecord.ps1 | 6 +- ServiceNow/Public/Get-ServiceNowRequest.ps1 | 4 - .../Public/Get-ServiceNowRequestedItem.ps1 | 4 - ServiceNow/Public/Get-ServiceNowTable.ps1 | 9 - .../Public/Get-ServiceNowTableEntry.ps1 | 4 - ServiceNow/Public/Get-ServiceNowUser.ps1 | 4 - ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 4 - .../Public/New-ServiceNowChangeRequest.ps1 | 4 +- ServiceNow/Public/New-ServiceNowIncident.ps1 | 4 +- ...ableEntry.ps1 => New-ServiceNowRecord.ps1} | 11 +- ...eEntry.ps1 => Remove-ServiceNowRecord.ps1} | 8 +- ...eEntry.ps1 => Update-ServiceNowRecord.ps1} | 3 +- ServiceNow/ServiceNow.psm1 | 3 + 17 files changed, 133 insertions(+), 124 deletions(-) rename ServiceNow/Public/{New-ServiceNowTableEntry.ps1 => New-ServiceNowRecord.ps1} (74%) rename ServiceNow/Public/{Remove-ServiceNowTableEntry.ps1 => Remove-ServiceNowRecord.ps1} (86%) rename ServiceNow/Public/{Update-ServiceNowTableEntry.ps1 => Update-ServiceNowRecord.ps1} (96%) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index d493792..17c39e2 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -1,17 +1,17 @@ -function Invoke-ServiceNowRestMethod { - <# - .SYNOPSIS - Retrieves records for the specified table - .DESCRIPTION - The Get-ServiceNowTable function retrieves records for the specified table - .INPUTS - None - .OUTPUTS - System.Management.Automation.PSCustomObject - .LINK - Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html - Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 +<# +.SYNOPSIS + Retrieves records for the specified table +.DESCRIPTION + The Get-ServiceNowTable function retrieves records for the specified table +.INPUTS + None +.OUTPUTS + System.Management.Automation.PSCustomObject +.LINK + Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html + Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 #> +function Invoke-ServiceNowRestMethod { [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding(SupportsPaging)] @@ -51,10 +51,6 @@ function Invoke-ServiceNowRestMethod { [Parameter()] [string] $Query, - # Maximum number of records to return - [Parameter()] - [int] $Limit, - # Fields to return [Parameter()] [Alias('Fields')] @@ -102,57 +98,35 @@ function Invoke-ServiceNowRestMethod { if ( $SysId ) { $params.Uri += "/$SysId" } - } else { + } + else { $params.Uri += $UriLeaf } if ( $Method -eq 'Get') { $Body = @{ 'sysparm_display_value' = $DisplayValues + 'sysparm_query' = (New-ServiceNowQuery -Filter $Filter -Sort $Sort) + 'sysparm_limit' = 10 } # Handle paging parameters - # If -Limit was provided, write a warning message, but prioritize it over -First. # The value of -First defaults to [uint64]::MaxValue if not specified. # If no paging information was provided, default to the legacy behavior, which was to return 10 records. - if ($PSBoundParameters.ContainsKey('Limit')) { - Write-Warning "The -Limit parameter is deprecated, and may be removed in a future release. Use the -First parameter instead." - $Body['sysparm_limit'] = $Limit - } elseif ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) { + if ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) { $Body['sysparm_limit'] = $PSCmdlet.PagingParameters.First - } else { - $Body['sysparm_limit'] = 10 } + # else { + # $Body['sysparm_limit'] = 10 + # } if ($PSCmdlet.PagingParameters.Skip) { $Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip } - if ($PSCmdlet.PagingParameters.IncludeTotalCount) { - # Accuracy is a double between 0.0 and 1.0 representing an estimated percentage accuracy. - # 0.0 means we have no idea and 1.0 means the number is exact. - - # ServiceNow does return this information in the X-Total-Count response header, - # but we're currently using Invoke-RestMethod to perform the API call, and Invoke-RestMethod - # does not provide the response headers, so we can't capture this info. - - # To properly support this parameter, we'd need to fall back on Invoke-WebRequest, read the - # X-Total-Count header of the response, and update this parameter after performing the API - # call. - - # Reference: - # https://developer.servicenow.com/app.do#!/rest_api_doc?v=jakarta&id=r_TableAPI-GET - - [double] $accuracy = 0.0 - $PSCmdlet.PagingParameters.NewTotalCount($PSCmdlet.PagingParameters.First, $accuracy) - } - - # Populate the query if ($Query) { $Body.sysparm_query = $Query - } else { - $body.sysparm_query = (New-ServiceNowQuery -Filter $Filter -Sort $Sort) } if ($Properties) { @@ -160,6 +134,12 @@ function Invoke-ServiceNowRestMethod { } } + # Populate the query + # else { + # $body['sysparm_query'] = (New-ServiceNowQuery -Filter $Filter -Sort $Sort) + # } + + if ( $Values ) { $Body = $Values | ConvertTo-Json @@ -173,44 +153,94 @@ function Invoke-ServiceNowRestMethod { Write-Verbose ($params | ConvertTo-Json) - $response = Invoke-RestMethod @params + # hide invoke-webrequest progress + $oldProgressPreference = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' + + $response = Invoke-WebRequest @params + + $content = $response.content | ConvertFrom-Json + if ( $content.PSobject.Properties.Name -contains "result" ) { + $records = @($content | Select-Object -ExpandProperty result) + } + else { + $records = @($content) + } + + # if option to get all records was provided, loop and get them all + if ( $PSCmdlet.PagingParameters.IncludeTotalCount.IsPresent ) { + + $totalRecordCount = [int]$response.Headers.'X-Total-Count' + Write-Verbose "Total number of records found was $totalRecordCount" + Write-Warning "Getting $($totalRecordCount - $PSCmdlet.PagingParameters.Skip) records, this could take a while..." + + $setPoint = $params.body.sysparm_offset + $params.body.sysparm_limit + + while ($totalRecordCount -gt $setPoint) { + + # up the offset so we get the next set of records + $params.body.sysparm_offset += $params.body.sysparm_limit + $setPoint = $params.body.sysparm_offset + $params.body.sysparm_limit + + $end = if ( $totalRecordCount -lt $setPoint ) { + $totalRecordCount + } + else { + $setPoint + } + + Write-Verbose ('getting {0}-{1} of {2}' -f ($params.body.sysparm_offset + 1), $end, $totalRecordCount) + $response = Invoke-WebRequest @params -Verbose:$false + + $content = $response.content | ConvertFrom-Json + if ( $content.PSobject.Properties.Name -contains "result" ) { + $records += $content | Select-Object -ExpandProperty result + } + else { + $records += $content + } + } + + if ( $totalRecordCount -ne ($records.count + $PSCmdlet.PagingParameters.Skip) ) { + Write-Error ('The expected number of records was not received. This can occur if your -First value, how many records retrieved at once, is too large. Lower this value and try again. Received: {0}, expected: {1}' -f $records.count, ($totalRecordCount - $PSCmdlet.PagingParameters.Skip)) + } + } + + # set the progress pref back now that done with invoke-webrequest + $ProgressPreference = $oldProgressPreference switch ($Method) { 'Get' { - if ( $response.PSobject.Properties.Name -contains "result" ) { - - $result = $response | Select-Object -ExpandProperty result - $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') - ForEach ($SNResult in $Result) { - ForEach ($Property in $ConvertToDateField) { - If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { + $ConvertToDateField = @('closed_at', 'expected_start', 'follow_up', 'opened_at', 'sys_created_on', 'sys_updated_on', 'work_end', 'work_start') + ForEach ($SNResult in $records) { + ForEach ($Property in $ConvertToDateField) { + If (-not [string]::IsNullOrEmpty($SNResult.$Property)) { + Try { + # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now + $CultureDateTimeFormat = (Get-Culture).DateTimeFormat + $DateFormat = $CultureDateTimeFormat.ShortDatePattern + $TimeFormat = $CultureDateTimeFormat.LongTimePattern + $DateTimeFormat = "$DateFormat $TimeFormat" + $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) + } + Catch { Try { - # Extract the default Date/Time formatting from the local computer's "Culture" settings, and then create the format to use when parsing the date/time from Service-Now - $CultureDateTimeFormat = (Get-Culture).DateTimeFormat - $DateFormat = $CultureDateTimeFormat.ShortDatePattern - $TimeFormat = $CultureDateTimeFormat.LongTimePattern - $DateTimeFormat = "$DateFormat $TimeFormat" + # Universal Format + $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } Catch { - Try { - # Universal Format - $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } Catch { - # If the local culture and universal formats both fail keep the property as a string (Do nothing) - $null = 'Silencing a PSSA alert with this line' - } + } + Catch { + # If the local culture and universal formats both fail keep the property as a string (Do nothing) + $null = 'Silencing a PSSA alert with this line' } } } } - } else { - $response } } { $_ -in 'Post', 'Patch' } { - $result = $response | Select-Object -ExpandProperty result + $records = $content | Select-Object -ExpandProperty result } 'Delete' { @@ -222,6 +252,5 @@ function Invoke-ServiceNowRestMethod { } } - $result - # Invoke-RestMethod -Uri $Uri -Credential $Credential -Body $Body -ContentType "application/json" | Select-Object -ExpandProperty Result + $records } diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 index 9a441c5..e5f303c 100644 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 @@ -11,10 +11,6 @@ function Get-ServiceNowChangeRequest { [ValidateSet('Desc', 'Asc')] [string] $OrderDirection = 'Desc', - # Maximum number of records to return - [Parameter()] - [int] $Limit, - # Fields to return [Parameter()] [Alias('Fields')] diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 index 46d87b2..d6a0e19 100644 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 @@ -11,10 +11,6 @@ function Get-ServiceNowConfigurationItem { [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', - # Maximum number of records to return - [Parameter()] - [int]$Limit, - # Fields to return [Parameter()] [Alias('Fields')] diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 index 01a7838..ea3013b 100644 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Get-ServiceNowIncident.ps1 @@ -11,10 +11,6 @@ function Get-ServiceNowIncident { [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', - # Maximum number of records to return - [Parameter()] - [int]$Limit, - # Fields to return [Parameter()] [Alias('Fields')] diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 18e9361..4f9b6b9 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -5,6 +5,7 @@ .DESCRIPTION Retrieve records from any table with the option to filter, sort, and choose fields. Given you know the table name, you shouldn't need any other 'Get-' function. + Paging is supported with -First, -Skip, and -IncludeTotalCount. .PARAMETER Table Name of the table to be queried, by either table name or class name @@ -58,6 +59,10 @@ Get-ServiceNowRecord -Table 'change request' -Filter @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') Get change requests opened in the last 30 days. Use class name as opposed to table name. +.EXAMPLE + Get-ServiceNowRecord -Table 'change request' -First 100 -IncludeTotalCount + Get all change requests, paging 100 at a time. + .INPUTS None @@ -74,7 +79,6 @@ function Get-ServiceNowRecord { Param ( [parameter(Mandatory)] - [ValidateNotNullOrEmpty()] [Alias('sys_class_name')] [string] $Table, diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 index 2b993fc..6d4d47f 100644 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequest.ps1 @@ -11,10 +11,6 @@ function Get-ServiceNowRequest { [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', - # Maximum number of records to return - [Parameter()] - [int]$Limit, - # Fields to return [Parameter()] [Alias('Fields')] diff --git a/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 index c2fdf01..365837f 100644 --- a/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 @@ -27,10 +27,6 @@ function Get-ServiceNowRequestedItem { [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', - # Maximum number of records to return - [parameter()] - [int]$Limit, - # Fields to return [Parameter()] [Alias('Fields')] diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 index 236cf91..7751e86 100644 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTable.ps1 @@ -25,10 +25,6 @@ function Get-ServiceNowTable { [Parameter()] [string] $Query, - # Maximum number of records to return - [Parameter()] - [int] $Limit, - # Fields to return [Parameter()] [Alias('Fields')] @@ -70,11 +66,6 @@ function Get-ServiceNowTable { ServiceNowSession = $ServiceNowSession } - # # Only add the Limit parameter if it was explicitly provided - if ($PSBoundParameters.ContainsKey('Limit')) { - $getServiceNowTableSplat.Add('Limit', $Limit) - } - # # Add all provided paging parameters ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 index 0d15366..35f31d0 100644 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 @@ -34,10 +34,6 @@ function Get-ServiceNowTableEntry { [ValidateSet('Desc', 'Asc')] [string] $OrderDirection = 'Desc', - # Maximum number of records to return - [parameter()] - [int] $Limit, - # Fields to return [Parameter()] [Alias('Fields')] diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 index a8bb560..76ec2bf 100644 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUser.ps1 @@ -11,10 +11,6 @@ function Get-ServiceNowUser{ [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', - # Maximum number of records to return - [Parameter()] - [int]$Limit, - # Fields to return [Parameter()] [Alias('Fields')] diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 index d5bb3f7..ea2080d 100644 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 @@ -11,10 +11,6 @@ function Get-ServiceNowUserGroup{ [ValidateSet('Desc', 'Asc')] [string]$OrderDirection = 'Desc', - # Maximum number of records to return - [Parameter()] - [int]$Limit, - # Fields to return [Parameter()] [Alias('Fields')] diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index 763bea4..8f3027f 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -152,7 +152,8 @@ function New-ServiceNowChangeRequest { If (($TableEntryValues.ContainsKey($Key) -eq $False)) { # Add the unique entry to the table entry values hash table $TableEntryValues.Add($Key, $CustomFields[$Key]) - } Else { + } + Else { # Capture the duplicate key name $Key } @@ -179,6 +180,7 @@ function New-ServiceNowChangeRequest { If ( $PSCmdlet.ShouldProcess($ShortDescription, 'Create new change request') ) { $response = Invoke-ServiceNowRestMethod @params If ($PassThru.IsPresent) { + $response.PSObject.TypeNames.Insert(0, "ServiceNow.ChangeRequest") $response } } diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 7a08328..72fb3eb 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -124,7 +124,8 @@ function New-ServiceNowIncident { If (($TableEntryValues.ContainsKey($Key) -eq $False)) { # Add the unique entry to the table entry values hash table $TableEntryValues.Add($Key, $CustomFields[$Key]) - } Else { + } + Else { # Capture the duplicate key name $Key } @@ -151,6 +152,7 @@ function New-ServiceNowIncident { If ( $PSCmdlet.ShouldProcess($ShortDescription, 'Create new incident') ) { $response = Invoke-ServiceNowRestMethod @params If ($PassThru.IsPresent) { + $response.PSObject.TypeNames.Insert(0, "ServiceNow.Incident") $response } } diff --git a/ServiceNow/Public/New-ServiceNowTableEntry.ps1 b/ServiceNow/Public/New-ServiceNowRecord.ps1 similarity index 74% rename from ServiceNow/Public/New-ServiceNowTableEntry.ps1 rename to ServiceNow/Public/New-ServiceNowRecord.ps1 index e5c65ee..42c4165 100644 --- a/ServiceNow/Public/New-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/New-ServiceNowRecord.ps1 @@ -1,4 +1,4 @@ -function New-ServiceNowTableEntry { +function New-ServiceNowRecord { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] @@ -37,9 +37,16 @@ function New-ServiceNowTableEntry { [switch] $PassThru ) + $invokeParams = $PSBoundParameters + $invokeParams.Remove('PassThru') | Out-Null + If ( $PSCmdlet.ShouldProcess($Table, 'Create new entry') ) { - $response = Invoke-ServiceNowRestMethod @PSBoundParameters -Method 'Post' + $response = Invoke-ServiceNowRestMethod @invokeParams -Method 'Post' If ($PassThru.IsPresent) { + $type = $script:ServiceNowTable | Where-Object {$_.Name -eq $Table -or $_.ClassName -eq $Table} | Select-Object -ExpandProperty Type + if ($type) { + $response | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } + } $response } } diff --git a/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 similarity index 86% rename from ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 rename to ServiceNow/Public/Remove-ServiceNowRecord.ps1 index 681044c..966c292 100644 --- a/ServiceNow/Public/Remove-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 @@ -1,12 +1,14 @@ -function Remove-ServiceNowTableEntry { +function Remove-ServiceNowRecord { [CmdletBinding(DefaultParameterSetName = 'Session', ConfirmImpact = 'High')] Param( # Table containing the entry we're deleting - [parameter(Mandatory)] + [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_class_name')] [string] $Table, # sys_id of the entry we're deleting - [parameter(Mandatory)] + [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] [string] $SysId, # Credential used to authenticate to ServiceNow diff --git a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Update-ServiceNowRecord.ps1 similarity index 96% rename from ServiceNow/Public/Update-ServiceNowTableEntry.ps1 rename to ServiceNow/Public/Update-ServiceNowRecord.ps1 index c192273..9bdc98b 100644 --- a/ServiceNow/Public/Update-ServiceNowTableEntry.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRecord.ps1 @@ -1,8 +1,9 @@ -function Update-ServiceNowTableEntry { +function Update-ServiceNowRecord { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] Param( # Table containing the entry we're updating [parameter(Mandatory)] + [Alias('sys_class_name')] [string] $Table, # sys_id of the entry we're updating diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index fcb3c26..269fabd 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -30,6 +30,9 @@ Export-ModuleMember -Variable ServiceNowSession $aliases = @{ 'Get-ServiceNowRequestItem' = 'Get-ServiceNowRequestedItem' 'Update-ServiceNowRequestItem' = 'Update-ServiceNowRequestedItem' + 'Remove-ServiceNowTableEntry' = 'Remove-ServiceNowRecord' + 'New-ServiceNowTableEntry' = 'New-ServiceNowRecord' + 'Update-ServiceNowTableEntry' = 'Update-ServiceNowRecord' } $aliases.GetEnumerator() | ForEach-Object { Set-Alias -Name $_.Key -Value $_.Value From 8816413621d6fa09ac06ad69b78ed506b5701875 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 13 May 2021 23:24:12 -0400 Subject: [PATCH 217/348] help updates --- ServiceNow/Public/New-ServiceNowIncident.ps1 | 3 -- ServiceNow/Public/New-ServiceNowRecord.ps1 | 38 +++++++++++++++++--- ServiceNow/ServiceNow.psd1 | 2 +- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 72fb3eb..816ba39 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -5,9 +5,6 @@ Generates a new ServiceNow Incident .DESCRIPTION Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API -.LINK -https://github.com/Snow-Shell/servicenow-powershell - .EXAMPLE Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. New-ServiceNowIncident -Caller "UserName" -ShortDescription = "New PS Incident" -Description = "This incident was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 diff --git a/ServiceNow/Public/New-ServiceNowRecord.ps1 b/ServiceNow/Public/New-ServiceNowRecord.ps1 index 42c4165..5b2dd50 100644 --- a/ServiceNow/Public/New-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/New-ServiceNowRecord.ps1 @@ -1,3 +1,35 @@ +<# +.SYNOPSIS + Create a new record in any table + +.DESCRIPTION + Create a new record in any table by specifying the table name and values required for that table + +.PARAMETER Table + Name or class name of the table to create the new record + +.PARAMETER Values + Hashtable with all the key/value pairs for the new record + +.PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + +.PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. + +.PARAMETER PassThru + If provided, the new record will be returned + +.EXAMPLE + New-ServiceNowTableEntry -Table incident -Values @{'Caller'='me';'short_description'='my issue'} + Create a new record in the incident table + +.INPUTS + None + +.OUTPUTS + PSCustomObject if PassThru provided +#> function New-ServiceNowRecord { [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] @@ -20,14 +52,12 @@ function New-ServiceNowRecord { # The URL for the ServiceNow instance being used [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] [ValidateNotNullOrEmpty()] - [string] - $ServiceNowURL, + [string] $ServiceNowURL, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] - [Hashtable] - $Connection, + [Hashtable] $Connection, [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 1f64875..704acdd 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -59,7 +59,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module - FunctionsToExport = @('Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowTableEntry','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowTableEntry','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowTableEntry') + FunctionsToExport = @('Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowRecord','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowRecord','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowRecord') # Variables to export from this module VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable' From 5760a841f884845fba7c7732283bff8a5ea173d6 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 13 May 2021 23:24:41 -0400 Subject: [PATCH 218/348] release prep --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81526ba..f7f538e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## v2.3 +- Add paging support to all `Get-` functions. Use `-First`, `-Skip`, and `-IncludeTotalCount` parameters. +- Additional pipline support added for Table and SysId parameters to pipe `Get-` functions to `Update-` and `Remove-`. +- ***Breaking change:*** deprecate `-Limit` parameter. The warning regarding deprecation went out over 2 years ago and now that paging has been implemented, it's a good time for this cleanup. Use `-First` instead. + ## v2.2 - Add advanced filtering and sorting. Initially implemented with `New-ServiceNowQuery` and `Get-ServiceNowRecord`. Filter with many different comparison operators as well as 'and', 'or', and 'group'ing. Sort ascending or descending against multiple fields. Comparison operators are the same as PowerShell for ease of use. Please use the GitHub Discussions section to provide feedback, thoughts, etc. - Add `Get-ServiceNowRecord`. This function implements the new advanced filtering and sorting. As long as you know your table name, this can replace all other Get functions. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 704acdd..5747774 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.2.0' +ModuleVersion = '2.3.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From c08085bab9ab8e715220e2fcbddf0b2381cd45f7 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 13 May 2021 23:28:51 -0400 Subject: [PATCH 219/348] release prep --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f538e..68d821e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ ## v2.3 -- Add paging support to all `Get-` functions. Use `-First`, `-Skip`, and `-IncludeTotalCount` parameters. +- Add paging support to all `Get-` functions. Use `-First`, `-Skip`, and `-IncludeTotalCount` parameters. In support of this, api calls have been changed from Invoke-RestMethod to Invoke-WebRequest. - Additional pipline support added for Table and SysId parameters to pipe `Get-` functions to `Update-` and `Remove-`. - ***Breaking change:*** deprecate `-Limit` parameter. The warning regarding deprecation went out over 2 years ago and now that paging has been implemented, it's a good time for this cleanup. Use `-First` instead. +- 'TableEntry' renamed to 'Record' for `New-`, `Update-`, and `Remove-` functions. Aliases added. ## v2.2 - Add advanced filtering and sorting. Initially implemented with `New-ServiceNowQuery` and `Get-ServiceNowRecord`. Filter with many different comparison operators as well as 'and', 'or', and 'group'ing. Sort ascending or descending against multiple fields. Comparison operators are the same as PowerShell for ease of use. Please use the GitHub Discussions section to provide feedback, thoughts, etc. From ba5ad9d645ffbb547ef9f778761bfb7c96927b54 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 19 May 2021 21:00:00 -0400 Subject: [PATCH 220/348] query operator fix for -notin and -notlike (#134) --- CHANGELOG.md | 4 ++++ ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 | 5 +++-- ServiceNow/ServiceNow.psd1 | 2 +- ServiceNow/config/main.json | 4 ++-- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68d821e..ae28e77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.3.1 +- Fix query operator -notin and -notlike which had a missing space +- Move verbose logging message in `Invoke-ServiceNowRestMethod` for number of records so it always shows. This is helpful when you change a filter and can see how many records would be returned without actually returning them. + ## v2.3 - Add paging support to all `Get-` functions. Use `-First`, `-Skip`, and `-IncludeTotalCount` parameters. In support of this, api calls have been changed from Invoke-RestMethod to Invoke-WebRequest. - Additional pipline support added for Table and SysId parameters to pipe `Get-` functions to `Update-` and `Remove-`. diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 17c39e2..0ea5f42 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -167,11 +167,12 @@ function Invoke-ServiceNowRestMethod { $records = @($content) } + $totalRecordCount = [int]$response.Headers.'X-Total-Count' + Write-Verbose "Total number of records for this query: $totalRecordCount" + # if option to get all records was provided, loop and get them all if ( $PSCmdlet.PagingParameters.IncludeTotalCount.IsPresent ) { - $totalRecordCount = [int]$response.Headers.'X-Total-Count' - Write-Verbose "Total number of records found was $totalRecordCount" Write-Warning "Getting $($totalRecordCount - $PSCmdlet.PagingParameters.Skip) records, this could take a while..." $setPoint = $params.body.sysparm_offset + $params.body.sysparm_limit diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 5747774..a4a53cc 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.3.0' +ModuleVersion = '2.3.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 2002ef0..87d5d3f 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -86,7 +86,7 @@ }, { "Name": "-notlike", - "QueryOperator": "NOTLIKE", + "QueryOperator": "NOT LIKE", "Description": "value is not found anywhere in field", "RequiresValue": true }, @@ -98,7 +98,7 @@ }, { "Name": "-notin", - "QueryOperator": "NOTIN", + "QueryOperator": "NOT IN", "Description": "field is populated by any value except for these", "RequiresValue": true }, From 8f57ed7d365741940d7e71655b73273779994c0e Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 24 May 2021 16:09:20 -0400 Subject: [PATCH 221/348] attachment pipeline enhancements --- CHANGELOG.md | 3 ++ .../Public/Add-ServiceNowAttachment.ps1 | 27 ++++++++++-------- .../Public/Get-ServiceNowAttachmentDetail.ps1 | 28 +++++++++++-------- ServiceNow/ServiceNow.psd1 | 2 +- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae28e77..ccae9e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2.3.2 +- Added ability to pipe to `Add-ServiceNowAttachment` and `Get-ServiceNowAttachmentDetail`. For example, `New-ServiceNowIncident @params -PassThru | Add-ServiceNowAttachment -File MyFile.txt`. This will create an incident and add an attachment in one step. + ## 2.3.1 - Fix query operator -notin and -notlike which had a missing space - Move verbose logging message in `Invoke-ServiceNowRestMethod` for number of records so it always shows. This is helpful when you change a filter and can see how many records would be returned without actually returning them. diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index d8801ac..11cedc3 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -17,12 +17,17 @@ Function Add-ServiceNowAttachment { .EXAMPLE Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt, .\File02.txt - + Upload one or more files to a ServiceNow ticket by specifing the number and table .EXAMPLE - Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt -ContentType 'text/plain' + New-ServiceNowIncident @params -PassThru | Add-ServiceNowAttachment -File File01.txt + + Create a new incident and add an attachment + .EXAMPLE + Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt -ContentType 'text/plain' + Upload a file and specify the MIME type (content type). Should only be required if the function cannot automatically determine the type. .EXAMPLE @@ -31,23 +36,21 @@ Function Add-ServiceNowAttachment { Upload a file and receive back the file details. .OUTPUTS - System.Management.Automation.PSCustomObject - - .NOTES - + System.Management.Automation.PSCustomObject if -PassThru provided #> [OutputType([PSCustomObject[]])] [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] Param( - # Object number - [Parameter(Mandatory)] - [string] $Number, - # Table containing the entry - [Parameter(Mandatory)] + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_class_name')] [string]$Table, + # Object number + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [string] $Number, + # Filter results by file name [parameter(Mandatory)] [ValidateScript( { @@ -92,7 +95,7 @@ Function Add-ServiceNowAttachment { $getSysIdParams = @{ Table = $Table - Query = (New-ServiceNowQuery -MatchExact @{'number' = $number }) + Query = (New-ServiceNowQuery -Filter @('number', '-eq', $number)) Properties = 'sys_id' Connection = $Connection Credential = $Credential diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 index 4fb175d..1ab6d19 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 @@ -27,20 +27,18 @@ Function Get-ServiceNowAttachmentDetail { .OUTPUTS System.Management.Automation.PSCustomObject - - .NOTES - #> [OutputType([System.Management.Automation.PSCustomObject[]])] [CmdletBinding(DefaultParameterSetName)] Param( # Table containing the entry - [Parameter(Mandatory)] + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_class_name')] [string] $Table, # Object number - [Parameter(Mandatory)] + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [string] $Number, # Filter results by file name @@ -76,7 +74,7 @@ Function Get-ServiceNowAttachmentDetail { $getSysIdParams = @{ Table = $Table - Query = (New-ServiceNowQuery -MatchExact @{'number' = $number }) + Query = (New-ServiceNowQuery -Filter @('number', '-eq', $number)) Properties = 'sys_id' Connection = $Connection Credential = $Credential @@ -89,10 +87,13 @@ Function Get-ServiceNowAttachmentDetail { $params = @{ Uri = '/attachment' - Query = (New-ServiceNowQuery -MatchExact @{ - table_name = $Table - table_sys_id = $sysId - }) + Query = ( + New-ServiceNowQuery -Filter @( + @('table_name', '-eq', $Table), + 'and', + @('table_sys_id', '-eq', $sysId) + ) + ) Connection = $Connection Credential = $Credential ServiceNowUrl = $ServiceNowURL @@ -101,10 +102,13 @@ Function Get-ServiceNowAttachmentDetail { $response = Invoke-ServiceNowRestMethod @params if ( $FileName ) { - $response = $response | Where-Object { $_.file_name -in $FileName } + $response | Where-Object { $_.file_name -in $FileName } + } + else { + $response } - $response | Update-ServiceNowDateTimeField + # $response | Update-ServiceNowDateTimeField } end {} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index a4a53cc..943e87d 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -20,7 +20,7 @@ CompanyName = 'None' Copyright = '(c) 2015-2021 Snow-Shell. All rights reserved.' # Description of the functionality provided by this module -Description = 'This module provides cmdlets allowing you to retrieve information from your ServiceNow instance''s REST API' +Description = 'Automate against ServiceNow service and asset management. This module can be used standalone or with Azure Automation.' # Minimum version of the Windows PowerShell engine required by this module # PowerShellVersion = '3.0' From ced5ccb1668028b3290cc76d2461536eb8982cc0 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 24 May 2021 16:16:53 -0400 Subject: [PATCH 222/348] update version --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 943e87d..f36fd6d 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.3.1' +ModuleVersion = '2.3.2' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 70d77097627b163214592799bd47362fcb5bef77 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 25 May 2021 11:00:23 -0400 Subject: [PATCH 223/348] point version to ps gallery --- Readme.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index b3a46cf..f8ad493 100644 --- a/Readme.md +++ b/Readme.md @@ -1,8 +1,10 @@ # ServiceNow -[![GitHub release](https://img.shields.io/github/release/Snow-Shell/servicenow-powershell.svg)](https://github.com/Snow-Shell/servicenow-powershell/releases/latest) [![GitHub license](https://img.shields.io/github/license/Snow-Shell/servicenow-powershell.svg)](LICENSE) +[![PowerShell Gallery Version](https://img.shields.io/powershellgallery/v/ServiceNow?style=plastic)](https://www.powershellgallery.com/packages/ServiceNow) +![PowerShell Gallery](https://img.shields.io/powershellgallery/dt/ServiceNow?style=plastic) +[![GitHub license](https://img.shields.io/github/license/Snow-Shell/servicenow-powershell.svg?style=plastic)](LICENSE) -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. +This PowerShell module provides a series of cmdlets for interacting with the [ServiceNow REST API](https://docs.servicenow.com/bundle/quebec-application-development/page/integrate/inbound-rest/concept/c_RESTAPI.html). **IMPORTANT:** Neither this module nor its creator are in any way affiliated with ServiceNow. From ed6448a2a1b7d34da84941e23572498f1d3c9450 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 27 May 2021 20:40:50 -0400 Subject: [PATCH 224/348] fix when no sort provided --- ServiceNow/Public/New-ServiceNowQuery.ps1 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index e8f82f2..d4a56bf 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -185,10 +185,13 @@ function New-ServiceNowQuery { } $orderList = $Sort - # see if we're working with 1 array or multidimensional array - # we want multidimensional so convert if not - if ($Sort[0].GetType().Name -eq 'String') { - $orderList = @(, $Sort) + + if ( $Sort ) { + # see if we're working with 1 array or multidimensional array + # we want multidimensional so convert if not + if ($Sort[0].GetType().Name -eq 'String') { + $orderList = @(, $Sort) + } } $query += for ($i = 0; $i -lt $orderList.Count; $i++) { From 8fd6b238ac7d09773d8b1b2e1e8f8dfe0e144512 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 27 May 2021 20:41:04 -0400 Subject: [PATCH 225/348] help update --- ServiceNow/Public/New-ServiceNowRecord.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/Public/New-ServiceNowRecord.ps1 b/ServiceNow/Public/New-ServiceNowRecord.ps1 index 5b2dd50..7d1a551 100644 --- a/ServiceNow/Public/New-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/New-ServiceNowRecord.ps1 @@ -21,7 +21,7 @@ If provided, the new record will be returned .EXAMPLE - New-ServiceNowTableEntry -Table incident -Values @{'Caller'='me';'short_description'='my issue'} + New-ServiceNowRecord -Table incident -Values @{'Caller'='me';'short_description'='my issue'} Create a new record in the incident table .INPUTS From 3aea3812b3154af1244dd9cb2e0633b565541bc9 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 27 May 2021 20:41:21 -0400 Subject: [PATCH 226/348] start of new ci --- .../New-ServiceNowConfigurationItem.ps1 | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 diff --git a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 new file mode 100644 index 0000000..c7568f0 --- /dev/null +++ b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 @@ -0,0 +1,150 @@ +<# +.SYNOPSIS +Generates a new configuration item + +.DESCRIPTION +Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API + +.EXAMPLE +Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. + New-ServiceNowIncident -Caller "UserName" -ShortDescription = "New PS Incident" -Description = "This incident was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 + +.EXAMPLE +Generate an Incident by "Splatting" all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow Instance): + + $IncidentParams = @{Caller = "UserName" + ShortDescription = "New PS Incident" + Description = "This incident was created from Powershell" + AssignmentGroup "ServiceDesk" + Comment "Inline Comment" + Category "Office" + Subcategory "Outlook" + ConfigurationItem UserPC1 + CustomFields = @{u_custom1 = "Custom Field Entry" + u_another_custom = "Related Test"} + } + New-ServiceNowIncident @Params + +#> +function New-ServiceNowConfigurationItem { + + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + + Param( + + # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) + [parameter(Mandatory)] + [string] $Name, + + # Short description of the incident + [parameter(Mandatory)] + [string] $ShortDescription, + + # Long description of the incident + [parameter()] + [string] $Description, + + # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) + [parameter()] + [string] $AssignmentGroup, + + # Comment to include in the ticket + [parameter()] + [string] $Comment, + + # Category of the incident (e.g. 'Network') + [parameter()] + [string] $Category, + + # Subcategory of the incident (e.g. 'Network') + [parameter()] + [string] $Subcategory, + + # sys_id of the configuration item of the incident + [parameter()] + [string] $ConfigurationItem, + + # custom fields as hashtable + [parameter()] + [hashtable] $CustomFields, + + #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [ValidateNotNullOrEmpty()] + [Hashtable] $Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession, + + [Parameter()] + [switch] $PassThru + ) + + begin {} + + process { + # Create a hash table of any defined parameters (not CustomFields) that have values + # $DefinedIncidentParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') + $definedParams = @{ + 'Name' = 'name' + } + $tableEntryValues = @{} + foreach ($key in $PSBoundParameters.Keys) { + if ($definedParams.$key) { + $tableEntryValues.Add($definedParams.$key, $PSBoundParameters.$key) + } + } + # ForEach ($Parameter in $DefinedIncidentParameters) { + # If ($null -ne $PSBoundParameters.$Parameter) { + # # Turn the defined parameter name into the ServiceNow attribute name + # $KeyToAdd = Switch ($Parameter) { + # AssignmentGroup { 'assignment_group'; break } + # Caller { 'caller_id'; break } + # Category { 'category'; break } + # Comment { 'comments'; break } + # ConfigurationItem { 'cmdb_ci'; break } + # Description { 'description'; break } + # ShortDescription { 'short_description'; break } + # Subcategory { 'subcategory'; break } + # } + # $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) + # } + # } + + # Add CustomFields hash pairs to the Table Entry Values hash table + $dupes = ForEach ($Key in $CustomFields.Keys) { + If ($TableEntryValues.ContainsKey($Key)) { + # Capture the duplicate key name + $Key + } + Else { + # Add the unique entry to the table entry values hash table + $TableEntryValues.Add($Key, $CustomFields[$Key]) + } + } + + # Throw an error if duplicate fields were provided + If ($dupes) { + throw ('Ticket fields may only be used once and you have redefined ''{0}'' in $CustomFields' -f ($dupes -join ",")) + } + + # Table Entry Splat + $params = @{ + Table = 'cmdb_ci' + Values = $TableEntryValues + Connection = $Connection + ServiceNowSession = $ServiceNowSession + PassThru = $true + } + + If ( $PSCmdlet.ShouldProcess($Name, 'Create new configuration item') ) { + $response = New-ServiceNowRecord @params + # $response = Invoke-ServiceNowRestMethod @params + If ($PassThru.IsPresent) { + $response.PSObject.TypeNames.Insert(0, "ServiceNow.ConfigurationItem") + $response + } + } + } +} From 17a6fd1e89825b3948b442ee761245b5a9d8d879 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sun, 30 May 2021 08:44:06 -0400 Subject: [PATCH 227/348] add - options for operators --- ServiceNow/Public/New-ServiceNowQuery.ps1 | 9 +++++---- ServiceNow/config/main.json | 12 ++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index d4a56bf..1b402b4 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -125,15 +125,15 @@ function New-ServiceNowQuery { # should be a join switch ($thisFilter[0]) { - 'and' { + { $_ -in 'and', '-and' } { '^' } - 'or' { + { $_ -in 'or', '-or' } { '^OR' } - 'group' { + { $_ -in 'group', '-group' } { '^NQ' } @@ -237,7 +237,8 @@ function New-ServiceNowQuery { $query -join '' - } else { + } + else { # Basic parameter set # Create StringBuilder diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 87d5d3f..643635f 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -132,11 +132,23 @@ "Description": "field starts with the value", "RequiresValue": true }, + { + "Name": "-startswith", + "QueryOperator": "STARTSWITH", + "Description": "field starts with the value", + "RequiresValue": true + }, { "Name": ".endswith", "QueryOperator": "%", "Description": "field ends with the value", "RequiresValue": true + }, + { + "Name": "-endswith", + "QueryOperator": "%", + "Description": "field ends with the value", + "RequiresValue": true } ] } \ No newline at end of file From 42527f0cc6cf055574d343d69374cde514847289 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sun, 30 May 2021 08:44:27 -0400 Subject: [PATCH 228/348] add new ci function, needs default fields --- .../New-ServiceNowConfigurationItem.ps1 | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 index c7568f0..ebb5dc5 100644 --- a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 @@ -85,7 +85,6 @@ function New-ServiceNowConfigurationItem { process { # Create a hash table of any defined parameters (not CustomFields) that have values - # $DefinedIncidentParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') $definedParams = @{ 'Name' = 'name' } @@ -95,22 +94,6 @@ function New-ServiceNowConfigurationItem { $tableEntryValues.Add($definedParams.$key, $PSBoundParameters.$key) } } - # ForEach ($Parameter in $DefinedIncidentParameters) { - # If ($null -ne $PSBoundParameters.$Parameter) { - # # Turn the defined parameter name into the ServiceNow attribute name - # $KeyToAdd = Switch ($Parameter) { - # AssignmentGroup { 'assignment_group'; break } - # Caller { 'caller_id'; break } - # Category { 'category'; break } - # Comment { 'comments'; break } - # ConfigurationItem { 'cmdb_ci'; break } - # Description { 'description'; break } - # ShortDescription { 'short_description'; break } - # Subcategory { 'subcategory'; break } - # } - # $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) - # } - # } # Add CustomFields hash pairs to the Table Entry Values hash table $dupes = ForEach ($Key in $CustomFields.Keys) { @@ -126,7 +109,7 @@ function New-ServiceNowConfigurationItem { # Throw an error if duplicate fields were provided If ($dupes) { - throw ('Ticket fields may only be used once and you have redefined ''{0}'' in $CustomFields' -f ($dupes -join ",")) + throw ('You are attempting to redefine a value, ''{0}'', with $CustomFields that is already set' -f ($dupes -join ",")) } # Table Entry Splat From 82997bb3137572d29a1efd396fee035a5c7fa712 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 2 Jun 2021 18:21:03 -0400 Subject: [PATCH 229/348] help updates --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 4f9b6b9..1a942dc 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -8,7 +8,8 @@ Paging is supported with -First, -Skip, and -IncludeTotalCount. .PARAMETER Table - Name of the table to be queried, by either table name or class name + Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. + You can also provide any table name ad hoc. .PARAMETER Properties Limit the fields returned to this list @@ -43,9 +44,9 @@ .EXAMPLE $filter = @('state', '-eq', '1'), - 'and', + '-and', @('short_description','-like', 'powershell'), - 'group', + '-group', @('state', '-eq', '2') PS > Get-ServiceNowRecord -Table incident -Filter $filter Get incident records where state equals New and short description contains the word powershell or state equals In Progress. From d0a81cd664b5b8e3d0c18e471484b9f965d13748 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 2 Jun 2021 18:21:18 -0400 Subject: [PATCH 230/348] operator updates --- ServiceNow/config/main.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 643635f..6aa551b 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -39,6 +39,11 @@ "Name": "sc_task", "ClassName": "Catalog Task", "Type": "ServiceNow.CatalogTask" + }, + { + "Name": "change_task", + "ClassName": "Change Task", + "Type": "ServiceNow.ChangeTask" } ], "FilterOperators": [ From 2b497a1012fcd18bbe9b4748d19f82fa2ff8cc25 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 2 Jun 2021 18:21:40 -0400 Subject: [PATCH 231/348] add arg completer for table param --- RELEASE.md | 0 ServiceNow/ServiceNow.psm1 | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..e69de29 diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 269fabd..b134814 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -9,6 +9,14 @@ $script:ServiceNowTable = $config.Tables Export-ModuleMember -Variable ServiceNowOperator, ServiceNowTable +$tableArgCompleterSb = { + $ServiceNowTable.ClassName | ForEach-Object { + '''{0}''' -f $_ + } +} + +Register-ArgumentCompleter -CommandName 'Get-ServiceNowRecord' -ParameterName 'Table' -ScriptBlock $tableArgCompleterSb + Write-Verbose 'Import everything in sub folders folder' foreach ($Folder in @('Private', 'Public')) { $Root = Join-Path -Path $PSScriptRoot -ChildPath $Folder From aed38900b9acccea55a213f40fa0e74d50612f08 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 2 Jun 2021 18:34:45 -0400 Subject: [PATCH 232/348] base new ci params --- .../New-ServiceNowConfigurationItem.ps1 | 39 ++++--------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 index ebb5dc5..cf33fe5 100644 --- a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 @@ -5,26 +5,14 @@ Generates a new configuration item .DESCRIPTION Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API +.PARAMETER Name + Name of the ci + .EXAMPLE Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. New-ServiceNowIncident -Caller "UserName" -ShortDescription = "New PS Incident" -Description = "This incident was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 .EXAMPLE -Generate an Incident by "Splatting" all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow Instance): - - $IncidentParams = @{Caller = "UserName" - ShortDescription = "New PS Incident" - Description = "This incident was created from Powershell" - AssignmentGroup "ServiceDesk" - Comment "Inline Comment" - Category "Office" - Subcategory "Outlook" - ConfigurationItem UserPC1 - CustomFields = @{u_custom1 = "Custom Field Entry" - u_another_custom = "Related Test"} - } - New-ServiceNowIncident @Params - #> function New-ServiceNowConfigurationItem { @@ -32,37 +20,26 @@ function New-ServiceNowConfigurationItem { Param( - # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) [parameter(Mandatory)] [string] $Name, - # Short description of the incident [parameter(Mandatory)] - [string] $ShortDescription, + [string] $Class, - # Long description of the incident [parameter()] [string] $Description, - # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) - [parameter()] - [string] $AssignmentGroup, - - # Comment to include in the ticket [parameter()] - [string] $Comment, + [string] $OperationalStatus, - # Category of the incident (e.g. 'Network') [parameter()] - [string] $Category, + [string] $Environment, - # Subcategory of the incident (e.g. 'Network') [parameter()] - [string] $Subcategory, + [string] $FQDN, - # sys_id of the configuration item of the incident [parameter()] - [string] $ConfigurationItem, + [ipaddress] $IpAddress, # custom fields as hashtable [parameter()] From 21390dc2906064f8f0bc7767e4c7ea603925c63c Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 4 Jun 2021 07:50:19 -0400 Subject: [PATCH 233/348] property update --- ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 index cf33fe5..22db539 100644 --- a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 @@ -63,7 +63,13 @@ function New-ServiceNowConfigurationItem { process { # Create a hash table of any defined parameters (not CustomFields) that have values $definedParams = @{ - 'Name' = 'name' + 'Name' = 'name' + 'Class' = 'sys_class_name' + 'Description' = 'description' + 'OperationalStatus' = 'operational_status' + 'Environment' = 'environment' + 'FQDN' = '' + 'IpAddress' = '' } $tableEntryValues = @{} foreach ($key in $PSBoundParameters.Keys) { From 0f81be8d481058443b05a910dbf4d097c369d9e6 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 7 Jun 2021 18:37:11 -0400 Subject: [PATCH 234/348] fix #136 --- ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 0ea5f42..fad6014 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -167,8 +167,16 @@ function Invoke-ServiceNowRestMethod { $records = @($content) } - $totalRecordCount = [int]$response.Headers.'X-Total-Count' - Write-Verbose "Total number of records for this query: $totalRecordCount" + $totalRecordCount = 0 + if ( $response.Headers.'X-Total-Count' ) { + if ($PSVersionTable.PSVersion.Major -lt 6) { + $totalRecordCount = [int]$response.Headers.'X-Total-Count' + } + else { + $totalRecordCount = [int]($response.Headers.'X-Total-Count'[0]) + } + Write-Verbose "Total number of records for this query: $totalRecordCount" + } # if option to get all records was provided, loop and get them all if ( $PSCmdlet.PagingParameters.IncludeTotalCount.IsPresent ) { From cbfee49b9fdd8629e3a222b8c766f8ed734ab739 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 7 Jun 2021 18:37:23 -0400 Subject: [PATCH 235/348] new ci --- .../New-ServiceNowConfigurationItem.ps1 | 75 +++++++++++-------- ServiceNow/Public/New-ServiceNowIncident.ps1 | 15 ++-- ServiceNow/ServiceNow.format.ps1xml | 16 +++- ServiceNow/ServiceNow.psd1 | 2 +- 4 files changed, 69 insertions(+), 39 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 index 22db539..8bdd91d 100644 --- a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 @@ -1,18 +1,41 @@ <# .SYNOPSIS -Generates a new configuration item + Create a new configuration item .DESCRIPTION -Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API + Create a new configuration item. You can create a specific class ci or root cmdb_ci. .PARAMETER Name Name of the ci + +.PARAMETER Class + Specify the class of the CI, eg. cmdb_ci_server. If not specified, cmdb_ci will be used. + +.PARAMETER Description + Description for the CI + +.PARAMETER OperationalStatus + Operational status value of the CI. Note, this is the numerical value, not display value. Eg. Use '1', not 'Operational'. + +.PARAMETER CustomField + Key/value pairs for fields not available as a function parameter, eg. @{'ip_address'='1.2.3.4'} + +.PARAMETER PassThru + Return the newly created CI + +.PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + +.PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. .EXAMPLE -Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. - New-ServiceNowIncident -Caller "UserName" -ShortDescription = "New PS Incident" -Description = "This incident was created from Powershell" -AssignmentGroup "ServiceDesk" -Comment "Inline Comment" -Category "Office" -Subcategory "Outlook" -ConfigurationItem UserPC1 + New-ServiceNowConfigurationItem -Name 'MyServer' -Class cmdb_ci_server + Create a new CI .EXAMPLE + New-ServiceNowConfigurationItem -Name 'MyServer' -Class cmdb_ci_server -PassThru + Create a new CI and return the newly created object to the pipeline #> function New-ServiceNowConfigurationItem { @@ -23,7 +46,7 @@ function New-ServiceNowConfigurationItem { [parameter(Mandatory)] [string] $Name, - [parameter(Mandatory)] + [parameter()] [string] $Class, [parameter()] @@ -32,18 +55,12 @@ function New-ServiceNowConfigurationItem { [parameter()] [string] $OperationalStatus, - [parameter()] - [string] $Environment, - - [parameter()] - [string] $FQDN, - - [parameter()] - [ipaddress] $IpAddress, - # custom fields as hashtable [parameter()] - [hashtable] $CustomFields, + [hashtable] $CustomField, + + [Parameter()] + [switch] $PassThru, #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] @@ -52,10 +69,7 @@ function New-ServiceNowConfigurationItem { [Parameter(ParameterSetName = 'Session')] [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession, - - [Parameter()] - [switch] $PassThru + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) begin {} @@ -67,9 +81,6 @@ function New-ServiceNowConfigurationItem { 'Class' = 'sys_class_name' 'Description' = 'description' 'OperationalStatus' = 'operational_status' - 'Environment' = 'environment' - 'FQDN' = '' - 'IpAddress' = '' } $tableEntryValues = @{} foreach ($key in $PSBoundParameters.Keys) { @@ -79,14 +90,14 @@ function New-ServiceNowConfigurationItem { } # Add CustomFields hash pairs to the Table Entry Values hash table - $dupes = ForEach ($Key in $CustomFields.Keys) { + $dupes = ForEach ($Key in $CustomField.Keys) { If ($TableEntryValues.ContainsKey($Key)) { # Capture the duplicate key name $Key } Else { # Add the unique entry to the table entry values hash table - $TableEntryValues.Add($Key, $CustomFields[$Key]) + $TableEntryValues.Add($Key, $CustomField[$Key]) } } @@ -97,16 +108,20 @@ function New-ServiceNowConfigurationItem { # Table Entry Splat $params = @{ - Table = 'cmdb_ci' - Values = $TableEntryValues - Connection = $Connection - ServiceNowSession = $ServiceNowSession - PassThru = $true + Table = 'cmdb_ci' + Values = $TableEntryValues + PassThru = $true + } + + if ($ServiceNowSession) { + $params.ServiceNowSession = $ServiceNowSession + } + else { + $params.Connection = $Connection } If ( $PSCmdlet.ShouldProcess($Name, 'Create new configuration item') ) { $response = New-ServiceNowRecord @params - # $response = Invoke-ServiceNowRestMethod @params If ($PassThru.IsPresent) { $response.PSObject.TypeNames.Insert(0, "ServiceNow.ConfigurationItem") $response diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 816ba39..597fb52 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -20,7 +20,7 @@ Generate an Incident by "Splatting" all fields used in the 1st example plus some Category "Office" Subcategory "Outlook" ConfigurationItem UserPC1 - CustomFields = @{u_custom1 = "Custom Field Entry" + CustomField = @{u_custom1 = "Custom Field Entry" u_another_custom = "Related Test"} } New-ServiceNowIncident @Params @@ -66,7 +66,8 @@ function New-ServiceNowIncident { # custom fields as hashtable [parameter()] - [hashtable] $CustomFields, + [Alias('CustomFields')] + [hashtable] $CustomField, # Credential used to authenticate to ServiceNow [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] @@ -95,7 +96,7 @@ function New-ServiceNowIncident { begin {} process { - # Create a hash table of any defined parameters (not CustomFields) that have values + # Create a hash table of any defined parameters (not CustomField) that have values $DefinedIncidentParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') $TableEntryValues = @{} ForEach ($Parameter in $DefinedIncidentParameters) { @@ -115,12 +116,12 @@ function New-ServiceNowIncident { } } - # Add CustomFields hash pairs to the Table Entry Values hash table - If ($null -ne $PSBoundParameters.CustomFields) { - $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { + # Add CustomField hash pairs to the Table Entry Values hash table + If ($null -ne $PSBoundParameters.CustomField) { + $DuplicateTableEntryValues = ForEach ($Key in $CustomField.Keys) { If (($TableEntryValues.ContainsKey($Key) -eq $False)) { # Add the unique entry to the table entry values hash table - $TableEntryValues.Add($Key, $CustomFields[$Key]) + $TableEntryValues.Add($Key, $CustomField[$Key]) } Else { # Capture the duplicate key name diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index db97bd6..44fa2bb 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -199,7 +199,15 @@ - 60 + 30 + + + + 32 + + + + 30 @@ -216,6 +224,12 @@ name + + sys_id + + + sys_class_name + category diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index f36fd6d..e78f377 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -59,7 +59,7 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module - FunctionsToExport = @('Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowRecord','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowRecord','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowRecord') + FunctionsToExport = @('New-ServiceNowConfigurationItem','Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowRecord','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowRecord','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowRecord') # Variables to export from this module VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable' From e3968f4bd4863058015ae74033abded0888f1cfa Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 7 Jun 2021 19:02:13 -0400 Subject: [PATCH 236/348] release prep --- CHANGELOG.md | 8 ++++++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccae9e4..55a54f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 2.4 +- Add `New-ServiceNowConfigurationItem`, [#109](https://github.com/Snow-Shell/servicenow-powershell/issues/109) +- Add grouping operators -and and -group as well as comparison operators -startwith and -endswith to keep with the -operator standard +- Add tab ahead/completion for the Table field in `Get-ServiceNowRecord`. This will allow you to either cycle through the different tables the module is aware of as well as provide your own value. +- Add Change Task to formatter and tab ahead +- Fix null index error when executing `New-ServiceNowQuery` without providing a value for `-Sort` +- Fix [#136](https://github.com/Snow-Shell/servicenow-powershell/issues/136) to account for PS v7.x Invoke-WebRequest headers all being arrays + ## 2.3.2 - Added ability to pipe to `Add-ServiceNowAttachment` and `Get-ServiceNowAttachmentDetail`. For example, `New-ServiceNowIncident @params -PassThru | Add-ServiceNowAttachment -File MyFile.txt`. This will create an incident and add an attachment in one step. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index e78f377..c65f753 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.3.2' +ModuleVersion = '2.4' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From a1a58e4e6035f4ceb1080873cf82d4828a297175 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 7 Jun 2021 20:41:49 -0400 Subject: [PATCH 237/348] changelog update --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55a54f0..d6d5d8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## 2.4 - Add `New-ServiceNowConfigurationItem`, [#109](https://github.com/Snow-Shell/servicenow-powershell/issues/109) -- Add grouping operators -and and -group as well as comparison operators -startwith and -endswith to keep with the -operator standard -- Add tab ahead/completion for the Table field in `Get-ServiceNowRecord`. This will allow you to either cycle through the different tables the module is aware of as well as provide your own value. +- Add grouping operators -and and -group as well as comparison operators -startwith and -endswith to `Get-ServiceNowRecord -Filter` to keep with the -operator standard +- Add tab ahead/completion for the `-Table` property in `Get-ServiceNowRecord`. This will allow you to cycle through the different tables the module is aware of. The values are the 'common' names, not table names so it's easier to understand for beginners. You can also provide any other table name ad hoc. - Add Change Task to formatter and tab ahead - Fix null index error when executing `New-ServiceNowQuery` without providing a value for `-Sort` - Fix [#136](https://github.com/Snow-Shell/servicenow-powershell/issues/136) to account for PS v7.x Invoke-WebRequest headers all being arrays From f4f0df7ec97d09b71033c714830c4ff2c42a0473 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 7 Jun 2021 21:00:57 -0400 Subject: [PATCH 238/348] Update CHANGELOG.md --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d5d8b..84aa1b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - Add tab ahead/completion for the `-Table` property in `Get-ServiceNowRecord`. This will allow you to cycle through the different tables the module is aware of. The values are the 'common' names, not table names so it's easier to understand for beginners. You can also provide any other table name ad hoc. - Add Change Task to formatter and tab ahead - Fix null index error when executing `New-ServiceNowQuery` without providing a value for `-Sort` -- Fix [#136](https://github.com/Snow-Shell/servicenow-powershell/issues/136) to account for PS v7.x Invoke-WebRequest headers all being arrays +- Fix [#136](https://github.com/Snow-Shell/servicenow-powershell/issues/136) to account for PS v7.x Invoke-WebRequest response headers all being arrays ## 2.3.2 - Added ability to pipe to `Add-ServiceNowAttachment` and `Get-ServiceNowAttachmentDetail`. For example, `New-ServiceNowIncident @params -PassThru | Add-ServiceNowAttachment -File MyFile.txt`. This will create an incident and add an attachment in one step. @@ -54,4 +54,4 @@ Be able to reference types from this config per table, removing the need to have - Add Add-ServiceNowAttachment - Add Get-ServiceNowAttachment - Add Get-ServiceNowAttachmentDetail -- Add Remove-ServiceNowAttachment \ No newline at end of file +- Add Remove-ServiceNowAttachment From 8595d5bb2b069fcc46facecf7038e8a0a6a47e77 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 8 Jun 2021 22:51:49 -0400 Subject: [PATCH 239/348] add custom variables --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 1 - ServiceNow/Public/Get-ServiceNowRecord.ps1 | 87 ++++++++++++++++--- ServiceNow/Public/New-ServiceNowQuery.ps1 | 1 - 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index fad6014..5c70393 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -44,7 +44,6 @@ function Invoke-ServiceNowRestMethod { [System.Collections.ArrayList] $Filter, [parameter()] - [ValidateNotNullOrEmpty()] [System.Collections.ArrayList] $Sort = @('opened_at', 'desc'), # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 1a942dc..75c4bb2 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -11,7 +11,7 @@ Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. You can also provide any table name ad hoc. -.PARAMETER Properties +.PARAMETER Property Limit the fields returned to this list .PARAMETER Filter @@ -26,12 +26,15 @@ Array or multidimensional array of fields to sort on. Each array should be of the format @(field, asc/desc). -.PARAMETER DisplayValues +.PARAMETER DisplayValue Option to display values for reference fields. 'false' will only retrieve the reference 'true' will only retrieve the underlying value 'all' will retrieve both. This is helpful when trying to translate values for a query. +.PARAMETER IncludeCustomVariable + Include custom variables in the return object. + .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance @@ -64,6 +67,10 @@ Get-ServiceNowRecord -Table 'change request' -First 100 -IncludeTotalCount Get all change requests, paging 100 at a time. +.EXAMPLE + Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -First 5 + Get the first 5 change requests and retrieve custom variable info + .INPUTS None @@ -84,8 +91,8 @@ function Get-ServiceNowRecord { [string] $Table, [Parameter()] - [Alias('Fields')] - [string[]] $Properties, + [Alias('Fields', 'Properties')] + [string[]] $Property, [parameter(ParameterSetName = 'AutomationFilter')] [parameter(ParameterSetName = 'SessionFilter')] @@ -98,7 +105,11 @@ function Get-ServiceNowRecord { [Parameter()] [ValidateSet('true', 'false', 'all')] - [string] $DisplayValues = 'true', + [Alias('DisplayValues')] + [string] $DisplayValue = 'true', + + [Parameter()] + [switch] $IncludeCustomVariable, [Parameter(Mandatory, ParameterSetName = 'AutomationQuery')] [parameter(Mandatory, ParameterSetName = 'AutomationFilter')] @@ -111,14 +122,68 @@ function Get-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $result = Invoke-ServiceNowRestMethod @PSBoundParameters + $invokeParams = @{ + Table = $Table + Properties = $Property + Filter = $Filter + Sort = $Sort + DisplayValues = $DisplayValue + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } - If ( $result -and -not $Properties) { - $type = $script:ServiceNowTable | Where-Object {$_.Name -eq $Table -or $_.ClassName -eq $Table} | Select-Object -ExpandProperty Type - if ($type) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } + $addedSysIdProp = $false + + # we need the sys_id value in order to get custom var data + # add it in if specific properties were requested and not part of the list + if ( $IncludeCustomVariable.IsPresent ) { + if ( $Property -and 'sys_id' -notin $Property ) { + $invokeParams.Properties += 'sys_id' + $addedSysIdProp = $true + } + } + + $result = Invoke-ServiceNowRestMethod @invokeParams + + if ( $result ) { + if ( $IncludeCustomVariable.IsPresent ) { + # for each record, get the variable names and then get the variable values + foreach ($record in $result) { + $customVarParams = @{ + Table = 'sc_item_option_mtom' + Properties = 'sc_item_option.item_option_new.name', 'sc_item_option.item_option_new.sys_name', 'sc_item_option.item_option_new.type' + Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22') + First = 1000 # hopefully there isn't more custom vars than this... + } + $customVars = Get-ServiceNowRecord @customVarParams + + if ( $customVars ) { + $customValues = Get-ServiceNowRecord -Table $Table -Filter @('sys_id', '-eq', $record.sys_id) -Properties ('variables.' + ($customVars.'sc_item_option.item_option_new.name' -join ',variables.')) + $customValues | Get-Member -MemberType NoteProperty | ForEach-Object { + $record | Add-Member @{ + $_.Name = $customValues."$($_.Name)" + } + } + } + + if ( $addedSysIdProp ) { + $record | Select-Object -Property * -ExcludeProperty sys_id + } + else { + $record + } + } + } + else { + + if ( -not $Property ) { + $type = $script:ServiceNowTable | Where-Object { $_.Name -eq $Table -or $_.ClassName -eq $Table } | Select-Object -ExpandProperty Type + if ($type) { + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } + } + } + $result } } - $result } diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index 1b402b4..9a294fc 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -90,7 +90,6 @@ function New-ServiceNowQuery { [System.Collections.ArrayList] $Filter, [parameter(ParameterSetName = 'Advanced')] - [ValidateNotNullOrEmpty()] [System.Collections.ArrayList] $Sort ) From a4d77e7ec7046dc206c812522f1d11e6ce630ece Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 8 Jun 2021 23:11:20 -0400 Subject: [PATCH 240/348] fix paging, prop name updates --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 13 ++++++----- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 23 +++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 5c70393..cdee3a9 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -52,13 +52,14 @@ function Invoke-ServiceNowRestMethod { # Fields to return [Parameter()] - [Alias('Fields')] - [string[]] $Properties, + [Alias('Fields', 'Properties')] + [string[]] $Property, # Whether or not to show human readable display values instead of machine values [Parameter()] [ValidateSet('true', 'false', 'all')] - [string] $DisplayValues = 'true', + [Alias('DisplayValues')] + [string] $DisplayValue = 'true', [Parameter()] [PSCredential] $Credential, @@ -104,7 +105,7 @@ function Invoke-ServiceNowRestMethod { if ( $Method -eq 'Get') { $Body = @{ - 'sysparm_display_value' = $DisplayValues + 'sysparm_display_value' = $DisplayValue 'sysparm_query' = (New-ServiceNowQuery -Filter $Filter -Sort $Sort) 'sysparm_limit' = 10 } @@ -128,8 +129,8 @@ function Invoke-ServiceNowRestMethod { $Body.sysparm_query = $Query } - if ($Properties) { - $Body.sysparm_fields = ($Properties -join ',').ToLower() + if ($Property) { + $Body.sysparm_fields = ($Property -join ',').ToLower() } } diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 75c4bb2..9d5eee9 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -122,15 +122,18 @@ function Get-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $invokeParams = @{ - Table = $Table - Properties = $Property - Filter = $Filter - Sort = $Sort - DisplayValues = $DisplayValue - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } + # $invokeParams = @{ + # Table = $Table + # Properties = $Property + # Filter = $Filter + # Sort = $Sort + # DisplayValues = $DisplayValue + # Connection = $Connection + # ServiceNowSession = $ServiceNowSession + # } + + $invokeParams = $PSBoundParameters + $invokeParams.Remove('IncludeCustomVariable') | Out-Null $addedSysIdProp = $false @@ -138,7 +141,7 @@ function Get-ServiceNowRecord { # add it in if specific properties were requested and not part of the list if ( $IncludeCustomVariable.IsPresent ) { if ( $Property -and 'sys_id' -notin $Property ) { - $invokeParams.Properties += 'sys_id' + $invokeParams.Property += 'sys_id' $addedSysIdProp = $true } } From 1719eabbb56c5df195d9e15084ea9e9cf036a830 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 9 Jun 2021 22:48:53 -0400 Subject: [PATCH 241/348] cleanup --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 9d5eee9..eaf324e 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -153,15 +153,20 @@ function Get-ServiceNowRecord { # for each record, get the variable names and then get the variable values foreach ($record in $result) { $customVarParams = @{ - Table = 'sc_item_option_mtom' - Properties = 'sc_item_option.item_option_new.name', 'sc_item_option.item_option_new.sys_name', 'sc_item_option.item_option_new.type' - Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22') - First = 1000 # hopefully there isn't more custom vars than this... + Table = 'sc_item_option_mtom' + Property = 'sc_item_option.item_option_new.name', 'sc_item_option.item_option_new.sys_name', 'sc_item_option.item_option_new.type' + Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22') + First = 1000 # hopefully there isn't more custom vars than this... } $customVars = Get-ServiceNowRecord @customVarParams if ( $customVars ) { - $customValues = Get-ServiceNowRecord -Table $Table -Filter @('sys_id', '-eq', $record.sys_id) -Properties ('variables.' + ($customVars.'sc_item_option.item_option_new.name' -join ',variables.')) + $customValueParams = @{ + Table = $Table + Filter = @('sys_id', '-eq', $record.sys_id) + Property = $customVars.'sc_item_option.item_option_new.name' | ForEach-Object { "variables.$_" } + } + $customValues = Get-ServiceNowRecord @customValueParams $customValues | Get-Member -MemberType NoteProperty | ForEach-Object { $record | Add-Member @{ $_.Name = $customValues."$($_.Name)" From 9e1cc73de2ee6fd7b5d12ece7c699ba3fd49955d Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 11 Jun 2021 14:49:48 -0400 Subject: [PATCH 242/348] move custom vars to separate property --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index eaf324e..735fdb7 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -34,6 +34,8 @@ .PARAMETER IncludeCustomVariable Include custom variables in the return object. + Some records may have associated custom variables, some may not. + For instance, an RITM may have custom variables, but the associated tasks may not. .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance @@ -58,7 +60,7 @@ .EXAMPLE Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Sort @('opened_at', 'desc'), @('state') Get incident records where state equals New and first sort by the field opened_at descending and then sort by the field state ascending - +] .EXAMPLE Get-ServiceNowRecord -Table 'change request' -Filter @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') Get change requests opened in the last 30 days. Use class name as opposed to table name. @@ -122,16 +124,6 @@ function Get-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - # $invokeParams = @{ - # Table = $Table - # Properties = $Property - # Filter = $Filter - # Sort = $Sort - # DisplayValues = $DisplayValue - # Connection = $Connection - # ServiceNowSession = $ServiceNowSession - # } - $invokeParams = $PSBoundParameters $invokeParams.Remove('IncludeCustomVariable') | Out-Null @@ -156,7 +148,7 @@ function Get-ServiceNowRecord { Table = 'sc_item_option_mtom' Property = 'sc_item_option.item_option_new.name', 'sc_item_option.item_option_new.sys_name', 'sc_item_option.item_option_new.type' Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22') - First = 1000 # hopefully there isn't more custom vars than this... + First = 1000 # hopefully there isn't more custom vars than this, but we need to overwrite the default of 10 } $customVars = Get-ServiceNowRecord @customVarParams @@ -167,11 +159,19 @@ function Get-ServiceNowRecord { Property = $customVars.'sc_item_option.item_option_new.name' | ForEach-Object { "variables.$_" } } $customValues = Get-ServiceNowRecord @customValueParams - $customValues | Get-Member -MemberType NoteProperty | ForEach-Object { - $record | Add-Member @{ - $_.Name = $customValues."$($_.Name)" + + # custom vars will be a separate property on the return object + $customVarsOut = $customVars | ForEach-Object { + $varName = $_.'sc_item_option.item_option_new.name' + [pscustomobject] @{ + Name = 'variables.{0}' -f $varName + DisplayName = $_.'sc_item_option.item_option_new.sys_name' + Value = $customValues."variables.$varName" } } + $record | Add-Member @{ + 'CustomVariable' = $customVarsOut + } } if ( $addedSysIdProp ) { From 9cffd890463b3af884540e95866c87ea63e856af Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 22 Jun 2021 22:07:11 -0400 Subject: [PATCH 243/348] Update ServiceNow.psd1 --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index c65f753..fc0336f 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.4' +ModuleVersion = '2.4.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 327e32544eded81c218f1c19b9f1b17ab8939575 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 22 Jun 2021 22:07:52 -0400 Subject: [PATCH 244/348] release prep --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84aa1b5..7e8e94f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2.4.1 +- Add `-IncludeCustomVariable` to `Get-ServiceNowRecord` to retrieve custom variables, eg. ritm form values, in addition to the standard fields. [#138](https://github.com/Snow-Shell/servicenow-powershell/discussions/138) + ## 2.4 - Add `New-ServiceNowConfigurationItem`, [#109](https://github.com/Snow-Shell/servicenow-powershell/issues/109) - Add grouping operators -and and -group as well as comparison operators -startwith and -endswith to `Get-ServiceNowRecord -Filter` to keep with the -operator standard From e65d5850a42ff482dcebeed2f5e5827d394f86cd Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 22 Jun 2021 22:08:37 -0400 Subject: [PATCH 245/348] help update --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 735fdb7..b9949f9 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -36,6 +36,7 @@ Include custom variables in the return object. Some records may have associated custom variables, some may not. For instance, an RITM may have custom variables, but the associated tasks may not. + A property named 'CustomVariable' will be added to the return object. .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance From 5c27ff1e5d7c64a17b3a4dec9f7e0a856d95a3a2 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sat, 26 Jun 2021 14:10:29 -0400 Subject: [PATCH 246/348] Update Readme.md --- Readme.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Readme.md b/Readme.md index f8ad493..5cbfb23 100644 --- a/Readme.md +++ b/Readme.md @@ -65,10 +65,6 @@ Get-ServiceNowRecord -Table incident -Filter $filter ### Retrieving an Incident Containing the Word 'PowerShell' -```PowerShell -Get-ServiceNowIncident -MatchContains @{short_description='PowerShell'} -``` -or new with v2.2 ```PowerShell Get-ServiceNowRecord -Table incident -Filter @('short_description','-eq','PowerShell') ``` @@ -76,7 +72,7 @@ Get-ServiceNowRecord -Table incident -Filter @('short_description','-eq','PowerS ### Update a Ticket ```PowerShell -Get-ServiceNowIncident -Limit 1 -MatchContains @{short_description='PowerShell'} | Update-ServiceNowIncident -Values @{comments='Updated via PowerShell'} +Get-ServiceNowRecord -First 1 -Filter @('short_description','-eq','PowerShell') | Update-ServiceNowIncident -Values @{comments='Updated via PowerShell'} ``` ### Creating an Incident with custom table entries From ef18db74cfcaf04129de3052ca1defb086391d35 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sat, 26 Jun 2021 14:14:46 -0400 Subject: [PATCH 247/348] Update Readme.md --- Readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 5cbfb23..e7f52d2 100644 --- a/Readme.md +++ b/Readme.md @@ -18,6 +18,8 @@ Building on the great work the community has done thus far, a lot of new updates - Pipeline support added to many functions - Standardizing on coding between all functions +***It is recommended to use `Get-ServiceNowRecord` instead of the other 'Get' functions.*** + ## Requirements Requires PowerShell 5.1 or above. @@ -66,7 +68,7 @@ Get-ServiceNowRecord -Table incident -Filter $filter ### Retrieving an Incident Containing the Word 'PowerShell' ```PowerShell -Get-ServiceNowRecord -Table incident -Filter @('short_description','-eq','PowerShell') +Get-ServiceNowRecord -Table incident -Filter @('short_description','-like','PowerShell') ``` ### Update a Ticket From ad95b2c92508f468d7e9e4b5a7ce88865a98ccd4 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 1 Jul 2021 15:49:14 -0400 Subject: [PATCH 248/348] add UseBasicParsing, #141 --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 1 + ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 1 + ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 1 + ServiceNow/Public/New-ServiceNowSession.ps1 | 16 ++++++++++------ 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index cdee3a9..630de2c 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -84,6 +84,7 @@ function Invoke-ServiceNowRestMethod { $params.Method = $Method $params.ContentType = 'application/json' + $params.UseBasicParsing = $true if ( $Table ) { # table can either be the actual table name or class name diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 11cedc3..3d19900 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -130,6 +130,7 @@ Function Add-ServiceNowAttachment { $invokeRestMethodSplat = $auth $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $Table, $sysId, $FileData.Name $invokeRestMethodSplat.Headers += @{'Content-Type' = $ContentType } + $invokeRestMethodSplat.UseBasicParsing = $true $invokeRestMethodSplat += @{ Method = 'POST' InFile = $FileData.FullName diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index d8968d3..e138b8d 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -107,6 +107,7 @@ Function Get-ServiceNowAttachment { # URI format: https://tenant.service-now.com/api/now/attachment/{sys_id}/file $params.Uri += '/attachment/' + $SysID + '/file' + $params.UseBasicParsing = $true If ($AppendNameWithSysID.IsPresent) { $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 0dc6cfa..ac08682 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -108,7 +108,8 @@ function New-ServiceNowSession { if ( $ApiVersion -le 0 ) { $version = '' - } else { + } + else { $version = ('/v{0}' -f $ApiVersion) } @@ -127,15 +128,16 @@ function New-ServiceNowSession { switch -Wildcard ($PSCmdLet.ParameterSetName) { 'OAuth*' { $params = @{ - Uri = 'https://{0}/oauth_token.do' -f $Url - Body = @{ + Uri = 'https://{0}/oauth_token.do' -f $Url + Body = @{ 'grant_type' = 'password' 'client_id' = $ClientCredential.UserName 'client_secret' = $ClientCredential.GetNetworkCredential().Password 'username' = $Credential.UserName 'password' = $Credential.GetNetworkCredential().Password } - Method = 'Post' + Method = 'Post' + UseBasicParsing = $true } # need to add this manually here, in addition to above, since we're making a rest call before our session is created @@ -143,7 +145,8 @@ function New-ServiceNowSession { $params.Add('Proxy', $Proxy) if ( $PSBoundParameters.ContainsKey('ProxyCredential') ) { $params.Add('ProxyCredential', $ProxyCredential) - } else { + } + else { $params.Add('ProxyUseDefaultCredentials', $true) } } @@ -196,7 +199,8 @@ function New-ServiceNowSession { if ( $PassThru ) { $newSession - } else { + } + else { $Script:ServiceNowSession = $newSession } } From 84db07d0689c11fb24463e7a76846855136cb12b Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 1 Jul 2021 15:53:46 -0400 Subject: [PATCH 249/348] release prep --- CHANGELOG.md | 3 +++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e8e94f..973508e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 2.4.2 +- Fix [#141](https://github.com/Snow-Shell/servicenow-powershell/issues/141), add `UseBasicParsing` to all API calls to keep AA from failing when IE hasn't been initialized + ## 2.4.1 - Add `-IncludeCustomVariable` to `Get-ServiceNowRecord` to retrieve custom variables, eg. ritm form values, in addition to the standard fields. [#138](https://github.com/Snow-Shell/servicenow-powershell/discussions/138) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index fc0336f..ee5d3af 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.4.1' +ModuleVersion = '2.4.2' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 5a9ffe443ce7f55bdd0f9ff9d4729c5feff94825 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 1 Jul 2021 16:24:37 -0400 Subject: [PATCH 250/348] remove cred params --- ServiceNow/Private/Get-ServiceNowAuth.ps1 | 30 ++-- .../Private/Invoke-ServiceNowRestMethod.ps1 | 33 ++-- .../Public/Add-ServiceNowAttachment.ps1 | 21 +-- .../Public/Export-ServiceNowAttachment.ps1 | 136 +++++++++++++++ .../Public/Get-ServiceNowAttachment.ps1 | 161 ++++++++---------- .../Public/Get-ServiceNowAttachmentDetail.ps1 | 115 ------------- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 1 - ServiceNow/Public/New-ServiceNowSession.ps1 | 25 ++- 8 files changed, 263 insertions(+), 259 deletions(-) create mode 100644 ServiceNow/Public/Export-ServiceNowAttachment.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 diff --git a/ServiceNow/Private/Get-ServiceNowAuth.ps1 b/ServiceNow/Private/Get-ServiceNowAuth.ps1 index e714831..ecc68c6 100644 --- a/ServiceNow/Private/Get-ServiceNowAuth.ps1 +++ b/ServiceNow/Private/Get-ServiceNowAuth.ps1 @@ -1,6 +1,7 @@ function Get-ServiceNowAuth { <# .SYNOPSIS + Return hashtable with base Uri and auth info. Add uri leaf, body, etc to output. .DESCRIPTION .INPUTS None @@ -12,15 +13,11 @@ function Get-ServiceNowAuth { [CmdletBinding()] Param ( [Parameter()] - [PSCredential] $Credential, - - [Parameter()] - [string] $ServiceNowURL, - - [Parameter()] + [Alias('C')] [hashtable] $Connection, [Parameter()] + [Alias('S')] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) @@ -31,9 +28,10 @@ function Get-ServiceNowAuth { $hashOut.Uri = $ServiceNowSession.BaseUri if ( $ServiceNowSession.AccessToken ) { $hashOut.Headers = @{ - 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken + 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken.GetNetworkCredential().password } - } else { + } + else { $hashOut.Credential = $ServiceNowSession.Credential } @@ -41,24 +39,22 @@ function Get-ServiceNowAuth { $hashOut.Proxy = $ServiceNowSession.Proxy if ( $ServiceNowSession.ProxyCredential ) { $hashOut.ProxyCredential = $ServiceNowSession.ProxyCredential - } else { + } + else { $hashOut.ProxyUseDefaultCredentials = $true } } - } elseif ( $Credential -and $ServiceNowURL ) { - Write-Warning -Message 'This authentication path, providing URL and credential directly, will be deprecated in a future release. Please use New-ServiceNowSession.' - $hashOut.Uri = 'https://{0}/api/now/v1' -f $ServiceNowURL - $hashOut.Credential = $Credential - - } elseif ( $Connection ) { + } + elseif ( $Connection ) { $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $hashOut.Credential = $Credential $hashOut.Uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri - } else { - throw "Exception: You must do one of the following to authenticate: `n 1. Call the New-ServiceNowSession cmdlet `n 2. Pass in an Azure Automation connection object `n 3. Pass in an endpoint and credential" + } + else { + throw "You must authenticate by either calling the New-ServiceNowSession cmdlet or passing in an Azure Automation connection object" } $hashOut diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index cdee3a9..60a5923 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -61,12 +61,6 @@ function Invoke-ServiceNowRestMethod { [Alias('DisplayValues')] [string] $DisplayValue = 'true', - [Parameter()] - [PSCredential] $Credential, - - [Parameter()] - [string] $ServiceNowUrl, - [Parameter()] [hashtable] $Connection, @@ -74,16 +68,12 @@ function Invoke-ServiceNowRestMethod { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $getAuth = @{ - Credential = $Credential - ServiceNowUrl = $ServiceNowUrl - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - $params = Get-ServiceNowAuth @getAuth + # get header/body auth values + $params = Get-ServiceNowAuth -C $Connection -S ServiceNowSession $params.Method = $Method $params.ContentType = 'application/json' + $params.UseBasicParsing = $true if ( $Table ) { # table can either be the actual table name or class name @@ -159,12 +149,21 @@ function Invoke-ServiceNowRestMethod { $response = Invoke-WebRequest @params - $content = $response.content | ConvertFrom-Json - if ( $content.PSobject.Properties.Name -contains "result" ) { - $records = @($content | Select-Object -ExpandProperty result) + # TODO: this could use some work + # checking for content is good, but at times we'll get content that's not valid + # eg. html content when a dev instance is hibernating + if ( $response.Content ) { + $content = $response.content | ConvertFrom-Json + if ( $content.PSobject.Properties.Name -contains "result" ) { + $records = @($content | Select-Object -ExpandProperty result) + } + else { + $records = @($content) + } } else { - $records = @($content) + # invoke-webrequest didn't throw an error per se, but we didn't get content back either + throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) } $totalRecordCount = 0 diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 11cedc3..1a6e299 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -106,13 +106,7 @@ Function Add-ServiceNowAttachment { # Use the number and table to determine the sys_id $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id - $getAuth = @{ - Credential = $Credential - ServiceNowUrl = $ServiceNowUrl - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - $auth = Get-ServiceNowAuth @getAuth + $auth = Get-ServiceNowAuth -C $Connection -S ServiceNowSession ForEach ($Object in $File) { $FileData = Get-ChildItem $Object -ErrorAction Stop @@ -137,10 +131,17 @@ Function Add-ServiceNowAttachment { If ($PSCmdlet.ShouldProcess("$Table $Number", 'Add attachment')) { Write-Verbose ($invokeRestMethodSplat | ConvertTo-Json) - $response = Invoke-RestMethod @invokeRestMethodSplat + $response = Invoke-WebRequest @invokeRestMethodSplat - If ($PassThru) { - $response.result + if ( $response.Content ) { + if ( $PassThru.IsPresent ) { + $content = $response.content | ConvertFrom-Json + $content.result + } + } + else { + # invoke-webrequest didn't throw an error, but we didn't get content back either + throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) } } } diff --git a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 new file mode 100644 index 0000000..12e7b53 --- /dev/null +++ b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 @@ -0,0 +1,136 @@ +Function Export-ServiceNowAttachment { + <# + .SYNOPSIS + Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + + .DESCRIPTION + Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + + .PARAMETER SysID + The ServiceNow sys_id of the file + + .PARAMETER FileName + File name the file is saved as. Do not include the path. + + .PARAMETER Destination + Path the file is saved to. Do not include the file name. + + .PARAMETER AllowOverwrite + Allows the function to overwrite the existing file. + + .PARAMETER AppendNameWithSysID + Adds the SysID to the file name. Intended for use when a ticket has multiple files with the same name. + + .EXAMPLE + Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' + + Save the attachment with the specified sys_id with a name of 'mynewfile.txt' + + .EXAMPLE + Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment + + Save all attachments from the ticket. Filenames will be assigned from the attachment name. + + .EXAMPLE + Get-ServiceNowAttachmentDetail -Number $Number -Table $Table | Get-ServiceNowAttachment -AppendNameWithSysID + + Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id. + + .EXAMPLE + Get-ServiceNowAttachmentDetail -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destination -AllowOverwrite + + Save all attachments from the ticket to the destination allowing for overwriting the destination file. + #> + + [CmdletBinding(DefaultParameterSetName = 'Table', SupportsShouldProcess = $true)] + Param( + + [Parameter(ParameterSetName = 'Table', Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_class_name')] + [string] $Table, + + [Parameter(ParameterSetName = 'Table', Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] + [string] $TableId, + + [Parameter(ParameterSetName = 'Attachment', Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] + [string] $SysId, + + [Parameter(ParameterSetName = 'Attachment', Mandatory, ValueFromPipelineByPropertyName)] + [Alias('file_name')] + [string] $FileName, + + # Out path to download files + [parameter()] + [ValidateScript( { + Test-Path $_ + })] + [string] $Destination = $PWD.Path, + + # Options impacting downloads + [parameter()] + [switch] $AllowOverwrite, + + # Options impacting downloads + [parameter()] + [switch] $AppendNameWithSysId, + + # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [ValidateNotNullOrEmpty()] + [Hashtable] $Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) + + begin { + $authParams = Get-ServiceNowAuth -C $Connection -S ServiceNowSession + } + + process { + + # URI format: https://tenant.service-now.com/api/now/attachment/{sys_id}/file + $params = $authParams.Clone() + + # if table record provided, get the attachment details + if ( $PSCmdlet.ParameterSetName -eq 'Table' ) { + + $attachmentListParams = @{ + Table = $Table + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + + # determine if tableid is the number or sysid + try { + [guid] $TableId + $attachmentListParams.SysId = $TableId + } + catch { + $attachmentListParams.Number = $TableId + } + } + + $params.Uri += '/attachment/' + $SysID + '/file' + + If ($AppendNameWithSysId.IsPresent) { + $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), $SysID, [io.path]::GetExtension($FileName) + } + $OutFile = $Null + $OutFile = Join-Path $Destination $FileName + + If ((Test-Path $OutFile) -and -not $AllowOverwrite.IsPresent) { + throw ('The file ''{0}'' already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file.' -f $OutFile) + } + + $params.OutFile = $OutFile + + If ($PSCmdlet.ShouldProcess("SysId $SysId", "Save attachment to file $OutFile")) { + Invoke-WebRequest @params + } + } + end {} +} diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index d8968d3..3d80404 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -1,88 +1,56 @@ + Function Get-ServiceNowAttachment { <# + .SYNOPSIS - Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. - + List details for ServiceNow attachments associated with a ticket number. + .DESCRIPTION - Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. - - .PARAMETER SysID - The ServiceNow sys_id of the file - + List details for ServiceNow attachments associated with a ticket number. + + .PARAMETER Number + ServiceNow ticket number + + .PARAMETER Table + ServiceNow ticket table name + .PARAMETER FileName - File name the file is saved as. Do not include the path. - - .PARAMETER Destination - Path the file is saved to. Do not include the file name. - - .PARAMETER AllowOverwrite - Allows the function to overwrite the existing file. - - .PARAMETER AppendNameWithSysID - Adds the SysID to the file name. Intended for use when a ticket has multiple files with the same name. - - .EXAMPLE - Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' - - Save the attachment with the specified sys_id with a name of 'mynewfile.txt' - + Filter for one or more file names. Works like a 'match' where partial file names are valid. + .EXAMPLE - Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment - - Save all attachments from the ticket. Filenames will be assigned from the attachment name. - - .EXAMPLE - Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -AppendNameWithSysID - - Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id. - + Get-ServiceNowAttachmentDetail -Number $Number -Table $Table + + List attachment details + .EXAMPLE - Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destionion -AllowOverwrite - - Save all attachments from the ticketto the destination allowing for overwriting the destination file. - - .NOTES - + Get-ServiceNowAttachmentDetail -Number $Number -Table $Table -FileName filename.txt,report.csv + + List details for only filename.txt and report.csv (if they exist). + + .OUTPUTS + System.Management.Automation.PSCustomObject #> - [CmdletBinding(DefaultParameterSetName, SupportsShouldProcess = $true)] - Param( - # Object number - [Parameter(Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $SysId, + [OutputType([System.Management.Automation.PSCustomObject[]])] + [CmdletBinding(DefaultParameterSetName = 'BySysId')] + Param( + # Table containing the entry [Parameter(Mandatory, ValueFromPipelineByPropertyName)] - [Alias('file_name')] - [string] $FileName, + [Alias('sys_class_name')] + [string] $Table, - # Out path to download files - [parameter()] - [ValidateScript( { - Test-Path $_ - })] - [string] $Destination = $PWD.Path, + # Object number + [Parameter(ParameterSetName = 'ByNumber', Mandatory)] + [string] $Number, - # Options impacting downloads - [parameter()] - [switch] $AllowOverwrite, + [Parameter(ParameterSetName = 'BySysId', Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] + [string] $SysId, - # Options impacting downloads + # Filter results by file name [parameter()] - [switch] $AppendNameWithSysID, - - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { $_ | Test-ServiceNowURL })] - [ValidateNotNullOrEmpty()] - [Alias('Url')] - [string] $ServiceNowURL, + [string[]] $FileName, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] @@ -97,35 +65,44 @@ Function Get-ServiceNowAttachment { begin {} process { - $getAuth = @{ - Credential = $Credential - ServiceNowUrl = $ServiceNowUrl - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - $params = Get-ServiceNowAuth @getAuth - - # URI format: https://tenant.service-now.com/api/now/attachment/{sys_id}/file - $params.Uri += '/attachment/' + $SysID + '/file' - If ($AppendNameWithSysID.IsPresent) { - $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), - $SysID, [io.path]::GetExtension($FileName) + if ( $PSCmdlet.ParameterSetName -eq 'ByNumber' ) { + $getSysIdParams = @{ + Table = $Table + Query = (New-ServiceNowQuery -Filter @('number', '-eq', $number)) + Properties = 'sys_id' + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + + # Use the number and table to determine the sys_id + $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id } - $OutFile = $Null - $OutFile = Join-Path $Destination $FileName - If ((Test-Path $OutFile) -and -not $AllowOverwrite.IsPresent) { - $ThrowMessage = "The file [{0}] already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file." -f $OutFile - Throw $ThrowMessage + $params = @{ + Uri = '/attachment' + Query = ( + New-ServiceNowQuery -Filter @( + @('table_name', '-eq', $Table), + 'and', + @('table_sys_id', '-eq', $sysId) + ) + ) + Connection = $Connection + ServiceNowSession = $ServiceNowSession } + $response = Invoke-ServiceNowRestMethod @params - $params.OutFile = $OutFile - - If ($PSCmdlet.ShouldProcess("SysId $SysId", "Save attachment to file $OutFile")) { - Invoke-RestMethod @params + if ( $FileName ) { + # TODO: move into query + $response | Where-Object { $_.file_name -in $FileName } + } + else { + $response } + # $response | Update-ServiceNowDateTimeField } + end {} } diff --git a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 b/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 deleted file mode 100644 index 1ab6d19..0000000 --- a/ServiceNow/Public/Get-ServiceNowAttachmentDetail.ps1 +++ /dev/null @@ -1,115 +0,0 @@ -Function Get-ServiceNowAttachmentDetail { - <# - .SYNOPSIS - List details for ServiceNow attachments associated with a ticket number. - - .DESCRIPTION - List details for ServiceNow attachments associated with a ticket number. - - .PARAMETER Number - ServiceNow ticket number - - .PARAMETER Table - ServiceNow ticket table name - - .PARAMETER FileName - Filter for one or more file names. Works like a 'match' where partial file names are valid. - - .EXAMPLE - Get-ServiceNowAttachmentDetail -Number $Number -Table $Table - - List attachment details - - .EXAMPLE - Get-ServiceNowAttachmentDetail -Number $Number -Table $Table -FileName filename.txt,report.csv - - List details for only filename.txt and report.csv (if they exist). - - .OUTPUTS - System.Management.Automation.PSCustomObject - #> - - [OutputType([System.Management.Automation.PSCustomObject[]])] - [CmdletBinding(DefaultParameterSetName)] - Param( - # Table containing the entry - [Parameter(Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_class_name')] - [string] $Table, - - # Object number - [Parameter(Mandatory, ValueFromPipelineByPropertyName)] - [string] $Number, - - # Filter results by file name - [parameter()] - [string[]] $FileName, - - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { $_ | Test-ServiceNowURL })] - [ValidateNotNullOrEmpty()] - [Alias('Url')] - [string] $ServiceNowURL, - - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [Hashtable] $Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - begin {} - - process { - - $getSysIdParams = @{ - Table = $Table - Query = (New-ServiceNowQuery -Filter @('number', '-eq', $number)) - Properties = 'sys_id' - Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL - ServiceNowSession = $ServiceNowSession - } - - # Use the number and table to determine the sys_id - $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id - - $params = @{ - Uri = '/attachment' - Query = ( - New-ServiceNowQuery -Filter @( - @('table_name', '-eq', $Table), - 'and', - @('table_sys_id', '-eq', $sysId) - ) - ) - Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL - ServiceNowSession = $ServiceNowSession - } - $response = Invoke-ServiceNowRestMethod @params - - if ( $FileName ) { - $response | Where-Object { $_.file_name -in $FileName } - } - else { - $response - } - - # $response | Update-ServiceNowDateTimeField - } - - end {} -} diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index b9949f9..d7a2f2f 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -194,5 +194,4 @@ function Get-ServiceNowRecord { $result } } - } diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 0dc6cfa..0feca74 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -108,7 +108,8 @@ function New-ServiceNowSession { if ( $ApiVersion -le 0 ) { $version = '' - } else { + } + else { $version = ('/v{0}' -f $ApiVersion) } @@ -143,18 +144,27 @@ function New-ServiceNowSession { $params.Add('Proxy', $Proxy) if ( $PSBoundParameters.ContainsKey('ProxyCredential') ) { $params.Add('ProxyCredential', $ProxyCredential) - } else { + } + else { $params.Add('ProxyUseDefaultCredentials', $true) } } - $token = Invoke-RestMethod @params - $newSession.Add('AccessToken', $token.access_token) - $newSession.Add('RefreshToken', $token.refresh_token) + $response = Invoke-WebRequest @params + + if ( $response.Content ) { + $token = $response.Content | ConvertFrom-Json + $newSession.Add('AccessToken', (New-Object System.Management.Automation.PSCredential('AccessToken', ($token.access_token | ConvertTo-SecureString -AsPlainText -Force)))) + $newSession.Add('RefreshToken', (New-Object System.Management.Automation.PSCredential('RefreshToken', ($token.refresh_token | ConvertTo-SecureString -AsPlainText -Force)))) + } + else { + # invoke-webrequest didn't throw an error, but we didn't get a token back either + throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) + } } 'AccessToken*' { - $newSession.Add('AccessToken', $AccessToken) + $newSession.Add('AccessToken', (New-Object System.Management.Automation.PSCredential('AccessToken', ($AccessToken | ConvertTo-SecureString -AsPlainText -Force)))) } 'BasicAuth*' { @@ -196,7 +206,8 @@ function New-ServiceNowSession { if ( $PassThru ) { $newSession - } else { + } + else { $Script:ServiceNowSession = $newSession } } From 7201854f5255f02cd00e5d5acf63710a3db06a54 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Jul 2021 10:13:47 -0400 Subject: [PATCH 251/348] remove cred-url --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 2 -- ServiceNow/Public/Get-ServiceNowAttachment.ps1 | 9 +-------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 29fa833..dc205e4 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -98,8 +98,6 @@ Function Add-ServiceNowAttachment { Query = (New-ServiceNowQuery -Filter @('number', '-eq', $number)) Properties = 'sys_id' Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index afb33c5..7705128 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -65,17 +65,10 @@ Function Get-ServiceNowAttachment { begin {} process { - $getAuth = @{ - Credential = $Credential - ServiceNowUrl = $ServiceNowUrl - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - $params = Get-ServiceNowAuth @getAuth + $params = Get-ServiceNowAuth -C $Connection -S ServiceNowSession # URI format: https://tenant.service-now.com/api/now/attachment/{sys_id}/file $params.Uri += '/attachment/' + $SysID + '/file' - $params.UseBasicParsing = $true if ( $PSCmdlet.ParameterSetName -eq 'ByNumber' ) { $getSysIdParams = @{ From f84667d9bc3f5a501c1acf942169f280ddbb01c3 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 2 Jul 2021 21:05:40 -0400 Subject: [PATCH 252/348] old get function cleanup --- ServiceNow/Private/Get-ServiceNowAuth.ps1 | 62 +++++++------ .../Private/Invoke-ServiceNowRestMethod.ps1 | 12 +-- .../Public/Add-ServiceNowAttachment.ps1 | 36 ++++---- .../Public/Get-ServiceNowAttachment.ps1 | 12 ++- .../Public/Get-ServiceNowChangeRequest.ps1 | 57 ------------ .../Get-ServiceNowConfigurationItem.ps1 | 57 ------------ ServiceNow/Public/Get-ServiceNowIncident.ps1 | 57 ------------ ServiceNow/Public/Get-ServiceNowRecord.ps1 | 1 + ServiceNow/Public/Get-ServiceNowRequest.ps1 | 57 ------------ .../Public/Get-ServiceNowRequestedItem.ps1 | 72 --------------- ServiceNow/Public/Get-ServiceNowTable.ps1 | 75 ---------------- .../Public/Get-ServiceNowTableEntry.ps1 | 90 ------------------- ServiceNow/Public/Get-ServiceNowUser.ps1 | 57 ------------ ServiceNow/Public/Get-ServiceNowUserGroup.ps1 | 57 ------------ ServiceNow/Public/New-ServiceNowSession.ps1 | 8 +- ServiceNow/Public/Remove-ServiceNowAuth.ps1 | 6 -- ServiceNow/Public/Set-ServiceNowAuth.ps1 | 35 -------- .../Public/Test-ServiceNowAuthIsSet.ps1 | 7 -- ServiceNow/Public/Update-ServiceNowNumber.ps1 | 15 +--- ServiceNow/Public/Update-ServiceNowRecord.ps1 | 31 +++---- 20 files changed, 79 insertions(+), 725 deletions(-) delete mode 100644 ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowIncident.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowRequest.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowTable.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowTableEntry.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowUser.ps1 delete mode 100644 ServiceNow/Public/Get-ServiceNowUserGroup.ps1 delete mode 100644 ServiceNow/Public/Remove-ServiceNowAuth.ps1 delete mode 100644 ServiceNow/Public/Set-ServiceNowAuth.ps1 delete mode 100644 ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 diff --git a/ServiceNow/Private/Get-ServiceNowAuth.ps1 b/ServiceNow/Private/Get-ServiceNowAuth.ps1 index ecc68c6..85fb68f 100644 --- a/ServiceNow/Private/Get-ServiceNowAuth.ps1 +++ b/ServiceNow/Private/Get-ServiceNowAuth.ps1 @@ -18,44 +18,48 @@ function Get-ServiceNowAuth { [Parameter()] [Alias('S')] - [hashtable] $ServiceNowSession = $script:ServiceNowSession + [hashtable] $ServiceNowSession ) - $hashOut = @{} + begin { + $hashOut = @{} + } - # Get credential and ServiceNow REST URL - if ( $ServiceNowSession.Count -gt 0 ) { - $hashOut.Uri = $ServiceNowSession.BaseUri - if ( $ServiceNowSession.AccessToken ) { - $hashOut.Headers = @{ - 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken.GetNetworkCredential().password - } - } - else { - $hashOut.Credential = $ServiceNowSession.Credential - } + process { - if ( $ServiceNowSession.Proxy ) { - $hashOut.Proxy = $ServiceNowSession.Proxy - if ( $ServiceNowSession.ProxyCredential ) { - $hashOut.ProxyCredential = $ServiceNowSession.ProxyCredential + if ( $ServiceNowSession.Count -gt 0 ) { + $hashOut.Uri = $ServiceNowSession.BaseUri + if ( $ServiceNowSession.AccessToken ) { + $hashOut.Headers = @{ + 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken.GetNetworkCredential().password + } } else { - $hashOut.ProxyUseDefaultCredentials = $true + $hashOut.Credential = $ServiceNowSession.Credential + } + + if ( $ServiceNowSession.Proxy ) { + $hashOut.Proxy = $ServiceNowSession.Proxy + if ( $ServiceNowSession.ProxyCredential ) { + $hashOut.ProxyCredential = $ServiceNowSession.ProxyCredential + } + else { + $hashOut.ProxyUseDefaultCredentials = $true + } } } - + elseif ( $Connection ) { + Write-Verbose 'connection' + $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) + $hashOut.Credential = $Credential + $hashOut.Uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri + } else { + throw "You must authenticate by either calling the New-ServiceNowSession cmdlet or passing in an Azure Automation connection object" + } } - elseif ( $Connection ) { - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $hashOut.Credential = $Credential - $hashOut.Uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri + end { + $hashOut } - else { - throw "You must authenticate by either calling the New-ServiceNowSession cmdlet or passing in an Azure Automation connection object" - } - - $hashOut } diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 60a5923..22b16d5 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -47,8 +47,8 @@ function Invoke-ServiceNowRestMethod { [System.Collections.ArrayList] $Sort = @('opened_at', 'desc'), # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [Parameter()] - [string] $Query, + # [Parameter()] + # [string] $Query, # Fields to return [Parameter()] @@ -69,7 +69,7 @@ function Invoke-ServiceNowRestMethod { ) # get header/body auth values - $params = Get-ServiceNowAuth -C $Connection -S ServiceNowSession + $params = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession $params.Method = $Method $params.ContentType = 'application/json' @@ -115,9 +115,9 @@ function Invoke-ServiceNowRestMethod { $Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip } - if ($Query) { - $Body.sysparm_query = $Query - } + # if ($Query) { + # $Body.sysparm_query = $Query + # } if ($Property) { $Body.sysparm_fields = ($Property -join ',').ToLower() diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index dc205e4..c3c867a 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -45,14 +45,18 @@ Function Add-ServiceNowAttachment { # Table containing the entry [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] - [string]$Table, + [string] $Table, - # Object number - [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'AutomationSysId', Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'SessionSysId', Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id')] + [string] $SysId, + + [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] + [Parameter(ParameterSetName = 'SessionNumber', Mandatory)] [string] $Number, - # Filter results by file name - [parameter(Mandatory)] + [Parameter(Mandatory)] [ValidateScript( { Test-Path $_ })] @@ -62,25 +66,14 @@ Function Add-ServiceNowAttachment { [Parameter()] [string] $ContentType, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { $_ | Test-ServiceNowURL })] - [ValidateNotNullOrEmpty()] - [Alias('Url')] - [string] $ServiceNowURL, - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [Parameter(ParameterSetName = 'AutomationSysId', Mandatory)] + [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] + [Parameter(ParameterSetName = 'SessionSysId')] + [Parameter(ParameterSetName = 'SessionNumber')] [ValidateNotNullOrEmpty()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, @@ -93,9 +86,10 @@ Function Add-ServiceNowAttachment { process { + $getSysIdParams = @{ Table = $Table - Query = (New-ServiceNowQuery -Filter @('number', '-eq', $number)) + Filter = @('number', '-eq', $number) Properties = 'sys_id' Connection = $Connection ServiceNowSession = $ServiceNowSession diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 7705128..a050bc9 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -73,7 +73,7 @@ Function Get-ServiceNowAttachment { if ( $PSCmdlet.ParameterSetName -eq 'ByNumber' ) { $getSysIdParams = @{ Table = $Table - Query = (New-ServiceNowQuery -Filter @('number', '-eq', $number)) + Filter = @('number', '-eq', $number) Properties = 'sys_id' Connection = $Connection ServiceNowSession = $ServiceNowSession @@ -85,12 +85,10 @@ Function Get-ServiceNowAttachment { $params = @{ Uri = '/attachment' - Query = ( - New-ServiceNowQuery -Filter @( - @('table_name', '-eq', $Table), - 'and', - @('table_sys_id', '-eq', $sysId) - ) + Filter = @( + @('table_name', '-eq', $Table), + 'and', + @('table_sys_id', '-eq', $sysId) ) Connection = $Connection ServiceNowSession = $ServiceNowSession diff --git a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 deleted file mode 100644 index e5f303c..0000000 --- a/ServiceNow/Public/Get-ServiceNowChangeRequest.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -function Get-ServiceNowChangeRequest { - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] - Param( - # Machine name of the field to order by - [Parameter()] - [string] $OrderBy = 'opened_at', - - # Direction of ordering (Desc/Asc) - [Parameter()] - [ValidateSet('Desc', 'Asc')] - [string] $OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]] $Properties, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter()] - [hashtable] $MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter()] - [hashtable] $MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [Parameter()] - [ValidateSet('true', 'false', 'all')] - [string] $DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { $_ | Test-ServiceNowURL })] - [Alias('Url')] - [string] $ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable] $Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'change_request' - - If ( $result -and -not $Properties) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.ChangeRequest") } - } - $result -} diff --git a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 deleted file mode 100644 index d6a0e19..0000000 --- a/ServiceNow/Public/Get-ServiceNowConfigurationItem.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -function Get-ServiceNowConfigurationItem { - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] - Param( - # Machine name of the field to order by - [Parameter()] - [string]$OrderBy = 'name', - - # Direction of ordering (Desc/Asc) - [Parameter()] - [ValidateSet('Desc', 'Asc')] - [string]$OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]]$Properties, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter()] - [hashtable]$MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter()] - [hashtable]$MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [Parameter()] - [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential]$Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript({$_ | Test-ServiceNowURL})] - [Alias('Url')] - [string]$ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable]$Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'cmdb_ci' - - If ( $result -and -not $Properties) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.ConfigurationItem") } - } - $result -} diff --git a/ServiceNow/Public/Get-ServiceNowIncident.ps1 b/ServiceNow/Public/Get-ServiceNowIncident.ps1 deleted file mode 100644 index ea3013b..0000000 --- a/ServiceNow/Public/Get-ServiceNowIncident.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -function Get-ServiceNowIncident { - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] - Param( - # Machine name of the field to order by - [Parameter()] - [string]$OrderBy = 'opened_at', - - # Direction of ordering (Desc/Asc) - [Parameter()] - [ValidateSet('Desc', 'Asc')] - [string]$OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]]$Properties, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter()] - [hashtable]$MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter()] - [hashtable]$MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [Parameter()] - [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential]$Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { $_ | Test-ServiceNowURL })] - [Alias('Url')] - [string]$ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable]$Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'incident' - - If ( $result -and -not $Properties) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.Incident") } - } - $result -} diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index d7a2f2f..0ece77c 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -185,6 +185,7 @@ function Get-ServiceNowRecord { } else { + # format the results if ( -not $Property ) { $type = $script:ServiceNowTable | Where-Object { $_.Name -eq $Table -or $_.ClassName -eq $Table } | Select-Object -ExpandProperty Type if ($type) { diff --git a/ServiceNow/Public/Get-ServiceNowRequest.ps1 b/ServiceNow/Public/Get-ServiceNowRequest.ps1 deleted file mode 100644 index 6d4d47f..0000000 --- a/ServiceNow/Public/Get-ServiceNowRequest.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -function Get-ServiceNowRequest { - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] - Param( - # Machine name of the field to order by - [Parameter()] - [string]$OrderBy = 'opened_at', - - # Direction of ordering (Desc/Asc) - [Parameter()] - [ValidateSet('Desc', 'Asc')] - [string]$OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]]$Properties, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter()] - [hashtable]$MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter()] - [hashtable]$MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [Parameter()] - [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential]$Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript({$_ | Test-ServiceNowURL})] - [Alias('Url')] - [string]$ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable]$Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sc_request' - - If ( $result -and -not $Properties) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.Request") } - } - $result -} diff --git a/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 b/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 deleted file mode 100644 index 365837f..0000000 --- a/ServiceNow/Public/Get-ServiceNowRequestedItem.ps1 +++ /dev/null @@ -1,72 +0,0 @@ -function Get-ServiceNowRequestedItem { -<# - .SYNOPSIS - Query for Requested Item (RITM) tickets. - - .DESCRIPTION - Query for Requested Item (RITM) tickets from the sc_req_item table. - - .EXAMPLE - Get-ServiceNowRequestedItem -MatchExact @{number='RITM0000001'} - - Return the details for RITM0000001 - - .OUTPUTS - System.Management.Automation.PSCustomObject -#> - - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] - param( - # Machine name of the field to order by - [parameter()] - [string]$OrderBy = 'opened_at', - - # Direction of ordering (Desc/Asc) - [parameter()] - [ValidateSet('Desc', 'Asc')] - [string]$OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]]$Properties, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter()] - [hashtable]$MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter()] - [hashtable]$MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [parameter()] - [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential]$Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable]$Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sc_req_item' - - If ( $result -and -not $Properties) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.RequestItem") } - } - $result -} diff --git a/ServiceNow/Public/Get-ServiceNowTable.ps1 b/ServiceNow/Public/Get-ServiceNowTable.ps1 deleted file mode 100644 index 7751e86..0000000 --- a/ServiceNow/Public/Get-ServiceNowTable.ps1 +++ /dev/null @@ -1,75 +0,0 @@ -function Get-ServiceNowTable { - <# - .SYNOPSIS - Retrieves records for the specified table - .DESCRIPTION - The Get-ServiceNowTable function retrieves records for the specified table - .INPUTS - None - .OUTPUTS - System.Management.Automation.PSCustomObject - .LINK - Service-Now Kingston REST Table API: https://docs.servicenow.com/bundle/kingston-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html - Service-Now Table API FAQ: https://hi.service-now.com/kb_view.do?sysparm_article=KB0534905 -#> - - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] - Param ( - # Name of the table we're querying (e.g. incidents) - [parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $Table, - - # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - [Parameter()] - [string] $Query, - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]] $Properties, - - # Whether or not to show human readable display values instead of machine values - [Parameter()] - [ValidateSet('true', 'false', 'all')] - [string] $DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('Url')] - [string]$ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable]$Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - # Table Splat - $getServiceNowTableSplat = @{ - Table = $Table - Query = $Query - Fields = $Properties - DisplayValues = $DisplayValues - Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL - ServiceNowSession = $ServiceNowSession - } - - # # Add all provided paging parameters - ($PSCmdlet.PagingParameters | Get-Member -MemberType Property).Name | ForEach-Object { - $getServiceNowTableSplat.Add($_, $PSCmdlet.PagingParameters.$_) - } - - Invoke-ServiceNowRestMethod @getServiceNowTableSplat -} diff --git a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 b/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 deleted file mode 100644 index 35f31d0..0000000 --- a/ServiceNow/Public/Get-ServiceNowTableEntry.ps1 +++ /dev/null @@ -1,90 +0,0 @@ -function Get-ServiceNowTableEntry { - <# - .SYNOPSIS - Wraps Get-ServiceNowQuery & Get-ServiceNowTable for easier custom table queries - .DESCRIPTION - Wraps Get-ServiceNowQuery & Get-ServiceNowTable for easier custom table queries. No formatting is provided on output. Every property is returned by default. - .EXAMPLE - Get-ServiceNowTableEntry -Table sc_req_item -Limit 1 - - Returns one request item (RITM) from the sc_req_item table - .EXAMPLE - $Record = Get-ServiceNowTableEntry -Table u_customtable -MatchExact @{number=$Number} - Update-ServiceNowTableEntry -SysID $Record.sys_id -Table u_customtable -Values @{comments='Ticket updated'} - - Utilize the returned object data with to provide the sys_id property required for updates and removals - .OUTPUTS - System.Management.Automation.PSCustomObject - .NOTES - - #> - - [CmdletBinding(DefaultParameterSetName, SupportsPaging)] - param( - # Table containing the entry we're deleting - [parameter(Mandatory)] - [string] $Table, - - # Machine name of the field to order by - [parameter()] - [string] $OrderBy = 'opened_at', - - # Direction of ordering (Desc/Asc) - [parameter()] - [ValidateSet('Desc', 'Asc')] - [string] $OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]] $Properties, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter()] - [hashtable] $MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter()] - [hashtable] $MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [parameter()] - [ValidateSet('true', 'false', 'all')] - [string] $DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { $_ | Test-ServiceNowURL })] - [Alias('Url')] - [string] $ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable] $Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - MatchExact = $MatchExact - OrderDirection = $OrderDirection - MatchContains = $MatchContains - } - $query = New-ServiceNowQuery @newServiceNowQuerySplat - - $paramsWithoutQuery = $PSBoundParameters - $paramsWithoutQuery.Remove('OrderBy') | Out-Null - $paramsWithoutQuery.Remove('MatchExact') | Out-Null - $paramsWithoutQuery.Remove('OrderDirection') | Out-Null - $paramsWithoutQuery.Remove('MatchContains') | Out-Null - - Invoke-ServiceNowRestMethod @paramsWithoutQuery -Query $query - # Get-ServiceNowTable @paramsWithoutQuery -Query $query -} diff --git a/ServiceNow/Public/Get-ServiceNowUser.ps1 b/ServiceNow/Public/Get-ServiceNowUser.ps1 deleted file mode 100644 index 76ec2bf..0000000 --- a/ServiceNow/Public/Get-ServiceNowUser.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -function Get-ServiceNowUser{ - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] - Param( - # Machine name of the field to order by - [Parameter()] - [string]$OrderBy = 'name', - - # Direction of ordering (Desc/Asc) - [Parameter()] - [ValidateSet('Desc', 'Asc')] - [string]$OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]]$Properties, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter()] - [hashtable]$MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter()] - [hashtable]$MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [Parameter()] - [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential]$Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript({$_ | Test-ServiceNowURL})] - [Alias('Url')] - [string]$ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable]$Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sys_user' - - If ( $result -and -not $Properties) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.UserAndUserGroup") } - } - $result -} diff --git a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 b/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 deleted file mode 100644 index ea2080d..0000000 --- a/ServiceNow/Public/Get-ServiceNowUserGroup.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -function Get-ServiceNowUserGroup{ - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName='Session', SupportsPaging)] - Param( - # Machine name of the field to order by - [Parameter()] - [string]$OrderBy = 'name', - - # Direction of ordering (Desc/Asc) - [Parameter()] - [ValidateSet('Desc', 'Asc')] - [string]$OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields')] - [string[]]$Properties, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter()] - [hashtable]$MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter()] - [hashtable]$MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [Parameter()] - [ValidateSet('true', 'false', 'all')] - [string]$DisplayValues = 'true', - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential]$Credential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript({$_ | Test-ServiceNowURL})] - [Alias('Url')] - [string]$ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [hashtable]$Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - $result = Get-ServiceNowTableEntry @PSBoundParameters -Table 'sys_user_group' - - If ( $result -and -not $Properties) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, "ServiceNow.UserAndUserGroup") } - } - $result -} diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 5613eae..d134b6f 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -151,13 +151,19 @@ function New-ServiceNowSession { } } + $oldProgressPreference = $ProgressPreference + $ProgressPreference = 'SilentlyContinue' + $response = Invoke-WebRequest @params + # set the progress pref back now that done with invoke-webrequest + $ProgressPreference = $oldProgressPreference + if ( $response.Content ) { $token = $response.Content | ConvertFrom-Json $newSession.Add('AccessToken', (New-Object System.Management.Automation.PSCredential('AccessToken', ($token.access_token | ConvertTo-SecureString -AsPlainText -Force)))) $newSession.Add('RefreshToken', (New-Object System.Management.Automation.PSCredential('RefreshToken', ($token.refresh_token | ConvertTo-SecureString -AsPlainText -Force)))) - } + } else { # invoke-webrequest didn't throw an error, but we didn't get a token back either throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) diff --git a/ServiceNow/Public/Remove-ServiceNowAuth.ps1 b/ServiceNow/Public/Remove-ServiceNowAuth.ps1 deleted file mode 100644 index c8117a5..0000000 --- a/ServiceNow/Public/Remove-ServiceNowAuth.ps1 +++ /dev/null @@ -1,6 +0,0 @@ -function Remove-ServiceNowAuth{ - - Write-Warning -Message 'Globally scoped variables have been removed from this module, therefore, Remove-ServiceNowAuth is not needed and will be deprecated' - - Return $true -} diff --git a/ServiceNow/Public/Set-ServiceNowAuth.ps1 b/ServiceNow/Public/Set-ServiceNowAuth.ps1 deleted file mode 100644 index 4501dc7..0000000 --- a/ServiceNow/Public/Set-ServiceNowAuth.ps1 +++ /dev/null @@ -1,35 +0,0 @@ -function Set-ServiceNowAuth { -<# - .SYNOPSIS - Set your Service-Now authentication credentials - - .DESCRIPTION - This cmdlet will set your Service-Now authentication credentials which will enable you to interact with Service-Now using the other cmdlets in the module - - .PARAMETER Url - The URL of your Service-Now instance - - .PARAMETER Credentials - Credentials to authenticate you to the Service-Now instance provided in the Url parameter - - .EXAMPLE - Set-ServiceNowAuth -Url tenant.service-now.com - - .NOTES - The URL should be the instance name portion of the FQDN for your instance. If you browse to https://yourinstance.service-now.com the URL required for the module is yourinstance.service-now.com -#> - [CmdletBinding()] - Param ( - [Parameter(Mandatory)] - [ValidateScript({$_ | Test-ServiceNowURL})] - [Alias('ServiceNowUrl')] - [string] $Url, - - [Parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [System.Management.Automation.PSCredential] $Credentials - ) - Write-Warning -Message 'Set-ServiceNowAuth will be deprecated in a future release. Please use New-ServiceNowSession. Also, the current default of v1 of the API will be deprecated in favor of the latest in a future release. Set-ServiceNowAuth will utilize v1. To test the latest API, use New-ServiceNowSession.' - New-ServiceNowSession -Url $Url -Credential $Credentials -ApiVersion 1 - return $true -} diff --git a/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 b/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 deleted file mode 100644 index dc36c7d..0000000 --- a/ServiceNow/Public/Test-ServiceNowAuthIsSet.ps1 +++ /dev/null @@ -1,7 +0,0 @@ -function Test-ServiceNowAuthIsSet{ - if ( $ServiceNowSession.Credential -or $ServiceNowSession.AccessToken ){ - return $true - }else{ - return $false - } -} diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 index d0927df..81a34b1 100644 --- a/ServiceNow/Public/Update-ServiceNowNumber.ps1 +++ b/ServiceNow/Public/Update-ServiceNowNumber.ps1 @@ -34,17 +34,6 @@ Function Update-ServiceNowNumber { [parameter()] [hashtable]$Values, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential]$Credential, - - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] @@ -65,11 +54,9 @@ Function Update-ServiceNowNumber { # Prep a splat to use the provided number to find the sys_id $getSysIdParams = @{ Table = $Table - Query = (New-ServiceNowQuery -MatchExact @{'number' = $number }) + Filter = @('number','-eq', $number) Properties = 'sys_id' Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } diff --git a/ServiceNow/Public/Update-ServiceNowRecord.ps1 b/ServiceNow/Public/Update-ServiceNowRecord.ps1 index 9bdc98b..1ae6b39 100644 --- a/ServiceNow/Public/Update-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRecord.ps1 @@ -1,37 +1,31 @@ function Update-ServiceNowRecord { - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + [CmdletBinding(DefaultParameterSetName = 'SessionSysId', SupportsShouldProcess)] Param( # Table containing the entry we're updating [parameter(Mandatory)] [Alias('sys_class_name')] [string] $Table, - # sys_id of the entry we're updating - [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'AutomationSysId', Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'SessionSysId', Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id')] [string] $SysId, + [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] + [Parameter(ParameterSetName = 'SessionNumber', Mandatory)] + [string] $Number, + # Hashtable of values to use as the record's properties [parameter()] [hashtable] $Values, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ServiceNowURL, - - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [Parameter(ParameterSetName = 'AutomationSysId', Mandatory)] + [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] + [Parameter(ParameterSetName = 'SessionSysId')] + [Parameter(ParameterSetName = 'SessionNumber')] [ValidateNotNullOrEmpty()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, @@ -48,8 +42,6 @@ function Update-ServiceNowRecord { SysId = $SysId Values = $Values Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } @@ -59,6 +51,5 @@ function Update-ServiceNowRecord { $response } } - } } From 366b795e10bd7cfbf83398a63bbc4b4e459e90a0 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 8 Jul 2021 09:15:13 -0400 Subject: [PATCH 253/348] combine old gets, prep for deprecation --- .../Public/Get-ServiceNowRecordInterim.ps1 | 70 +++++++++++++ ServiceNow/ServiceNow.format.ps1xml | 97 +++++++++++++++++++ ServiceNow/ServiceNow.psd1 | 6 +- ServiceNow/ServiceNow.psm1 | 26 +++-- 4 files changed, 191 insertions(+), 8 deletions(-) create mode 100644 ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 diff --git a/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 b/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 new file mode 100644 index 0000000..7c4f10e --- /dev/null +++ b/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 @@ -0,0 +1,70 @@ +function Get-ServiceNowRecordInterim { + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] + Param( + # Machine name of the field to order by + [Parameter()] + [string] $OrderBy = 'opened_at', + + # Direction of ordering (Desc/Asc) + [Parameter()] + [ValidateSet('Desc', 'Asc')] + [string] $OrderDirection = 'Desc', + + # Fields to return + [Parameter()] + [Alias('Fields', 'Properties')] + [string[]] $Property, + + # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) + [Parameter()] + [hashtable] $MatchExact = @{}, + + # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) + [Parameter()] + [hashtable] $MatchContains = @{}, + + # Whether or not to show human readable display values instead of machine values + [Parameter()] + [ValidateSet('true', 'false', 'all')] + [Alias('DisplayValues')] + [string] $DisplayValue = 'true', + + [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [ValidateNotNullOrEmpty()] + [hashtable] $Connection, + + [Parameter(ParameterSetName = 'Session')] + [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) + + Write-Warning ('{0} will be deprecated in the near future. Please use Get-ServiceNowRecord instead.' -f $PSCmdlet.MyInvocation.InvocationName) + + $table = $ServiceNowTable | Where-Object { $PSCmdlet.MyInvocation.InvocationName.ToLower().Replace('get-servicenow', '') -eq $_.ClassName.Replace(' ', '').ToLower() } + + $newServiceNowQuerySplat = @{ + OrderBy = $OrderBy + MatchExact = $MatchExact + OrderDirection = $OrderDirection + MatchContains = $MatchContains + } + $query = New-ServiceNowQuery @newServiceNowQuerySplat + + $params = @{ + Table = $table.Name + Query = $query + DisplayValue = $DisplayValue + First = $PSCmdlet.PagingParameters.First + Skip = $PSCmdlet.PagingParameters.Skip + IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + $result = Invoke-ServiceNowRestMethod @params + + If ( $result -and -not $Properties) { + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $table.Type) } + } + $result +} \ No newline at end of file diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index 44fa2bb..7e6b199 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -375,5 +375,102 @@ + + ServiceNow.ChangeTask + + ServiceNow.ChangeTask + + + + + + 12 + + + + 10 + + + + 21 + + + + 25 + + + + 15 + + + + + + + number + + + state + + + opened_at + + + short_description + + + + $_.change_request.display_value + + + + + + + + + ServiceNow.Attachment + + ServiceNow.Attachment + + + + + + 25 + + + + 15 + + + + 20 + + + + 32 + + + + + + + file_name + + + size_bytes + + + table_name + + + table_sys_id + + + + + + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index ee5d3af..0ac6c02 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -59,10 +59,12 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module - FunctionsToExport = @('New-ServiceNowConfigurationItem','Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Get-ServiceNowAttachmentDetail','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowRecord','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowRecord','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowRecord') + FunctionsToExport = @('Get-ServiceNowRecordInterim','New-ServiceNowConfigurationItem','Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Export-ServiceNowAttachment','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowRecord','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowRecord','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowRecord') # Variables to export from this module - VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable' + VariablesToExport = @('ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable') + + AliasesToExport = @('gsnr','Get-ServiceNowIncident','Get-ServiceNowChangeRequest', 'Get-ServiceNowConfigurationItem', 'Get-ServiceNowRequest', 'Get-ServiceNowRequestedItem', 'Get-ServiceNowUser', 'Get-ServiceNowUserGroup') # List of all modules packaged with this module # ModuleList = @() diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index b134814..2a7a533 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -15,7 +15,13 @@ $tableArgCompleterSb = { } } -Register-ArgumentCompleter -CommandName 'Get-ServiceNowRecord' -ParameterName 'Table' -ScriptBlock $tableArgCompleterSb +# assign the table arg completer to functions +@( + 'Get-ServiceNowRecord', + 'Get-ServiceNowAttachment' +) | ForEach-Object { + Register-ArgumentCompleter -CommandName $_ -ParameterName 'Table' -ScriptBlock $tableArgCompleterSb +} Write-Verbose 'Import everything in sub folders folder' foreach ($Folder in @('Private', 'Public')) { @@ -36,11 +42,19 @@ $Script:ServiceNowSession = @{} Export-ModuleMember -Variable ServiceNowSession $aliases = @{ - 'Get-ServiceNowRequestItem' = 'Get-ServiceNowRequestedItem' - 'Update-ServiceNowRequestItem' = 'Update-ServiceNowRequestedItem' - 'Remove-ServiceNowTableEntry' = 'Remove-ServiceNowRecord' - 'New-ServiceNowTableEntry' = 'New-ServiceNowRecord' - 'Update-ServiceNowTableEntry' = 'Update-ServiceNowRecord' + 'Get-ServiceNowRequestItem' = 'Get-ServiceNowRequestedItem' + 'Get-ServiceNowIncident' = 'Get-ServiceNowRecordInterim' + 'Get-ServiceNowChangeRequest' = 'Get-ServiceNowRecordInterim' + 'Get-ServiceNowConfigurationItem' = 'Get-ServiceNowRecordInterim' + 'Get-ServiceNowRequest' = 'Get-ServiceNowRecordInterim' + 'Get-ServiceNowRequestedItem' = 'Get-ServiceNowRecordInterim' + 'Get-ServiceNowUser' = 'Get-ServiceNowRecordInterim' + 'Get-ServiceNowUserGroup' = 'Get-ServiceNowRecordInterim' + 'Update-ServiceNowRequestItem' = 'Update-ServiceNowRequestedItem' + 'Remove-ServiceNowTableEntry' = 'Remove-ServiceNowRecord' + 'New-ServiceNowTableEntry' = 'New-ServiceNowRecord' + 'Update-ServiceNowTableEntry' = 'Update-ServiceNowRecord' + 'gsnr' = 'Get-ServiceNowRecord' } $aliases.GetEnumerator() | ForEach-Object { Set-Alias -Name $_.Key -Value $_.Value From 868ca165491b0e4234ba4613408585f32e29c2a8 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 8 Jul 2021 09:15:50 -0400 Subject: [PATCH 254/348] reinstate query param until Get deprecation --- ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 22b16d5..c9650a6 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -47,8 +47,8 @@ function Invoke-ServiceNowRestMethod { [System.Collections.ArrayList] $Sort = @('opened_at', 'desc'), # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) - # [Parameter()] - # [string] $Query, + [Parameter()] + [string] $Query, # Fields to return [Parameter()] @@ -78,7 +78,7 @@ function Invoke-ServiceNowRestMethod { if ( $Table ) { # table can either be the actual table name or class name # look up the actual table name - $tableName = $script:ServiceNowTable | Where-Object { $_.Name -eq $Table -or $_.ClassName -eq $Table } | Select-Object -ExpandProperty Name + $tableName = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } | Select-Object -ExpandProperty Name # if not in our lookup, just use the table name as provided if ( -not $tableName ) { $tableName = $Table @@ -115,9 +115,9 @@ function Invoke-ServiceNowRestMethod { $Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip } - # if ($Query) { - # $Body.sysparm_query = $Query - # } + if ($Query) { + $Body.sysparm_query = $Query + } if ($Property) { $Body.sysparm_fields = ($Property -join ',').ToLower() From c441b3d85e5356b070657563c5ad5e1f002c208d Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 8 Jul 2021 09:16:40 -0400 Subject: [PATCH 255/348] add Id, Name functionality --- .../Public/Get-ServiceNowAttachment.ps1 | 150 ++++++++++++------ ServiceNow/Public/Get-ServiceNowRecord.ps1 | 86 ++++++++-- 2 files changed, 171 insertions(+), 65 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index a050bc9..1783b17 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -3,107 +3,153 @@ Function Get-ServiceNowAttachment { <# .SYNOPSIS - List details for ServiceNow attachments associated with a ticket number. + Retrieve attachment details .DESCRIPTION - List details for ServiceNow attachments associated with a ticket number. - - .PARAMETER Number - ServiceNow ticket number + Retrieve attachment details via table record or by advanced filtering. .PARAMETER Table - ServiceNow ticket table name + Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. + You can also provide any table name ad hoc. + + .PARAMETER Id + Either the record sys_id or number. + If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. .PARAMETER FileName - Filter for one or more file names. Works like a 'match' where partial file names are valid. + Filter for a specific file name or part of a file name. + + .PARAMETER Filter + Array or multidimensional array of fields and values to filter on. + Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group'. + For a complete list of comparison operators, see $script:ServiceNowOperator and use Name in your filter. + See the examples. + Also, see https://docs.servicenow.com/bundle/quebec-platform-user-interface/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html + for how to represent date values with javascript. + + .PARAMETER Sort + Array or multidimensional array of fields to sort on. + Each array should be of the format @(field, asc/desc). + + .PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + + .PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. + + .EXAMPLE + Get-ServiceNowAttachment -Id 'INC1234567' + + Get attachment details for a specific record .EXAMPLE - Get-ServiceNowAttachmentDetail -Number $Number -Table $Table + Get-ServiceNowAttachment -Id 'INC1234567' -FileName image.jpg - List attachment details + Get attachment details for a specific record where file names match all or part of image.jpg .EXAMPLE - Get-ServiceNowAttachmentDetail -Number $Number -Table $Table -FileName filename.txt,report.csv + Get-ServiceNowAttachment -Filter @('size_bytes', '-gt', '1000000') - List details for only filename.txt and report.csv (if they exist). + Get attachment details where size is greater than 1M. + .INPUTS + Table, Id + .OUTPUTS System.Management.Automation.PSCustomObject #> [OutputType([System.Management.Automation.PSCustomObject[]])] - [CmdletBinding(DefaultParameterSetName = 'BySysId')] + [CmdletBinding(DefaultParameterSetName = 'Filter', SupportsPaging)] Param( - # Table containing the entry - [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'Table', Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, - # Object number - [Parameter(ParameterSetName = 'ByNumber', Mandatory)] - [string] $Number, + [Parameter(ParameterSetName = 'Id', Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'Table', Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id', 'SysId', 'number')] + [string] $Id, - [Parameter(ParameterSetName = 'BySysId', Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $SysId, - - # Filter results by file name [parameter()] - [string[]] $FileName, + [string] $FileName, + + [Parameter()] + [System.Collections.ArrayList] $Filter, - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [parameter()] [ValidateNotNullOrEmpty()] + [System.Collections.ArrayList] $Sort, + + [Parameter()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) begin {} process { - $params = Get-ServiceNowAuth -C $Connection -S ServiceNowSession - - # URI format: https://tenant.service-now.com/api/now/attachment/{sys_id}/file - $params.Uri += '/attachment/' + $SysID + '/file' + $params = @{ + UriLeaf = '/attachment' + First = $PSCmdlet.PagingParameters.First + Skip = $PSCmdlet.PagingParameters.Skip + IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } - if ( $PSCmdlet.ParameterSetName -eq 'ByNumber' ) { - $getSysIdParams = @{ - Table = $Table - Filter = @('number', '-eq', $number) - Properties = 'sys_id' + if ( $PSCmdlet.ParameterSetName -in 'Table', 'Id' ) { + $getParams = @{ + Id = $Id + Property = 'sys_class_name', 'sys_id' Connection = $Connection ServiceNowSession = $ServiceNowSession } + if ( $Table ) { + $getParams.Table = $Table + } + $tableRecord = Get-ServiceNowRecord @getParams - # Use the number and table to determine the sys_id - $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id - } - - $params = @{ - Uri = '/attachment' - Filter = @( - @('table_name', '-eq', $Table), + if ( -not $tableRecord ) { + Write-Error "Record not found for Id '$Id'" + continue + } + + $params.Filter = @( + @('table_name', '-eq', $tableRecord.sys_class_name), 'and', - @('table_sys_id', '-eq', $sysId) + @('table_sys_id', '-eq', $tableRecord.sys_id) ) - Connection = $Connection - ServiceNowSession = $ServiceNowSession } - $response = Invoke-ServiceNowRestMethod @params if ( $FileName ) { - # TODO: move into query - $response | Where-Object { $_.file_name -in $FileName } + if ( $params.Filter ) { + $params.Filter += 'and', @('file_name', '-like', $FileName) + } + else { + $params.Filter = @('file_name', '-like', $FileName) + } } - else { + + if ( $Filter ) { + if ( $params.Filter ) { + $params.Filter += 'and', $Filter + } + else { + $params.Filter = $Filter + } + } + + $response = Invoke-ServiceNowRestMethod @params + + if ( $response ) { + $response | ForEach-Object { $_.PSObject.TypeNames.Insert(0, 'ServiceNow.Attachment') } $response } - # $response | Update-ServiceNowDateTimeField } end {} diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 0ece77c..1c17ae0 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -86,23 +86,30 @@ function Get-ServiceNowRecord { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'SessionFilter', SupportsPaging)] + [CmdletBinding(DefaultParameterSetName = 'Id', SupportsPaging)] + [Alias('gsnr')] Param ( - [parameter(Mandatory)] + [Parameter(ParameterSetName = 'Table', Mandatory)] [Alias('sys_class_name')] [string] $Table, + [Parameter(ParameterSetName = 'Id', Mandatory, Position = 0)] + [Parameter(ParameterSetName = 'Table')] + [Alias('sys_id', 'number')] + [string] $Id, + + [Parameter()] + [string] $Name, + [Parameter()] [Alias('Fields', 'Properties')] [string[]] $Property, - [parameter(ParameterSetName = 'AutomationFilter')] - [parameter(ParameterSetName = 'SessionFilter')] + [Parameter()] [System.Collections.ArrayList] $Filter, - [parameter(ParameterSetName = 'AutomationFilter')] - [parameter(ParameterSetName = 'SessionFilter')] + [parameter()] [ValidateNotNullOrEmpty()] [System.Collections.ArrayList] $Sort, @@ -114,22 +121,70 @@ function Get-ServiceNowRecord { [Parameter()] [switch] $IncludeCustomVariable, - [Parameter(Mandatory, ParameterSetName = 'AutomationQuery')] - [parameter(Mandatory, ParameterSetName = 'AutomationFilter')] - [ValidateNotNullOrEmpty()] + # [Parameter(Mandatory, ParameterSetName = 'AutomationTable')] + # [Parameter(Mandatory, ParameterSetName = 'AutomationId')] + # [ValidateNotNullOrEmpty()] + # [AllowNull()] + [Parameter()] [hashtable] $Connection, - [Parameter(ParameterSetName = 'SessionQuery')] - [Parameter(ParameterSetName = 'SessionFilter')] - [ValidateNotNullOrEmpty()] + # [Parameter(ParameterSetName = 'SessionTable')] + # [Parameter(ParameterSetName = 'SessionId')] + # [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) + # it's easier this way to pass everything to invoke-servicenowrestmethod given paging params, etc $invokeParams = $PSBoundParameters $invokeParams.Remove('IncludeCustomVariable') | Out-Null + $invokeParams.Remove('Id') | Out-Null + $invokeParams.Remove('Name') | Out-Null - $addedSysIdProp = $false + if ( $Id ) { + if ( $Id -match '[a-zA-Z0-9]{32}' ) { + if ( $PSCmdlet.ParameterSetName -like '*Id' ) { + throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567.' + } + $idFilter = @('sys_id', '-eq', $Id) + } + else { + if ( $PSCmdlet.ParameterSetName -like '*Id' ) { + # get table name from prefix if only Id was provided + $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $Id.ToLower().StartsWith($_.NumberPrefix) } | Select-Object -ExpandProperty Name + if ( $thisTable ) { + $invokeParams.Table = $thisTable + } + else { + throw ('Prefix not found for Id ''{0}''. Known prefixes are {1}.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + } + } + $idFilter = @('number', '-eq', $Id) + } + + if ( $invokeParmas.Filter ) { + $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter + } + else { + $invokeParams.Filter = $idFilter + } + } + + if ( $Name ) { + # determine the field we should compare for 'name' and add the filter + $thisNameField = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } | Select-Object -ExpandProperty TableNameField + if ( $thisNameField ) { + if ( $invokeParmas.Filter ) { + $invokeParams.Filter = $invokeParams.Filter, 'and', @($thisNameField, '-like', $Name) + } + else { + $invokeParams.Filter = @($thisNameField, '-like', $Name) + } + } + } + + $addedSysIdProp = $false # we need the sys_id value in order to get custom var data # add it in if specific properties were requested and not part of the list if ( $IncludeCustomVariable.IsPresent ) { @@ -139,6 +194,11 @@ function Get-ServiceNowRecord { } } + if ( $Table -eq 'attachment' ) { + $invokeParams.Remove('Table') | Out-Null + $invokeParams.UriLeaf = '/attachment' + } + $result = Invoke-ServiceNowRestMethod @invokeParams if ( $result ) { From 1182ee7a84f3680c33f48612b24954e8c5e4cdd2 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 8 Jul 2021 09:18:08 -0400 Subject: [PATCH 256/348] config updates to support table prefix and name field --- ServiceNow/config/main.json | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 6aa551b..0faf6a8 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -3,47 +3,62 @@ { "Name": "incident", "ClassName": "Incident", - "Type": "ServiceNow.Incident" + "Type": "ServiceNow.Incident", + "NumberPrefix": "inc", + "TableNameField": "short_description" }, { "Name": "change_request", "ClassName": "Change Request", - "Type": "ServiceNow.ChangeRequest" + "Type": "ServiceNow.ChangeRequest", + "NumberPrefix": "chg", + "TableNameField": "short_description" }, { "Name": "cmdb_ci", "ClassName": "Configuration Item", - "Type": "ServiceNow.ConfigurationItem" + "Type": "ServiceNow.ConfigurationItem", + "TableNameField": "name" }, { "Name": "sc_request", "ClassName": "Request", - "Type": "ServiceNow.Request" + "Type": "ServiceNow.Request", + "NumberPrefix": "req", + "TableNameField": "short_description" }, { "Name": "sc_req_item", "ClassName": "Requested Item", - "Type": "ServiceNow.RequestItem" + "Type": "ServiceNow.RequestItem", + "NumberPrefix": "ritm", + "TableNameField": "short_description" }, { "Name": "sys_user", "ClassName": "User", - "Type": "ServiceNow.UserAndUserGroup" + "Type": "ServiceNow.UserAndUserGroup", + "TableNameField": "name" }, { "Name": "sys_user_group", "ClassName": "User Group", - "Type": "ServiceNow.UserAndUserGroup" + "Type": "ServiceNow.UserAndUserGroup", + "TableNameField": "name" }, { "Name": "sc_task", "ClassName": "Catalog Task", - "Type": "ServiceNow.CatalogTask" + "Type": "ServiceNow.CatalogTask", + "NumberPrefix": "sctask", + "TableNameField": "short_description" }, { "Name": "change_task", "ClassName": "Change Task", - "Type": "ServiceNow.ChangeTask" + "Type": "ServiceNow.ChangeTask", + "NumberPrefix": "ctask", + "TableNameField": "short_description" } ], "FilterOperators": [ From 0edf4d3a6dd365f68e473e374be5b3c46d4ce60d Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 8 Jul 2021 09:18:37 -0400 Subject: [PATCH 257/348] id, name functionality --- .../Public/Add-ServiceNowAttachment.ps1 | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index c3c867a..67e9f28 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -40,21 +40,20 @@ Function Add-ServiceNowAttachment { #> [OutputType([PSCustomObject[]])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess)] Param( # Table containing the entry - [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, - [Parameter(ParameterSetName = 'AutomationSysId', Mandatory, ValueFromPipelineByPropertyName)] - [Parameter(ParameterSetName = 'SessionSysId', Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $SysId, + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id', 'SysId', 'number')] + [string] $Id, - [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] - [Parameter(ParameterSetName = 'SessionNumber', Mandatory)] - [string] $Number, + # [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] + # [Parameter(ParameterSetName = 'SessionNumber', Mandatory)] + # [string] $Number, [Parameter(Mandatory)] [ValidateScript( { @@ -66,39 +65,41 @@ Function Add-ServiceNowAttachment { [Parameter()] [string] $ContentType, + # Allow the results to be shown + [Parameter()] + [switch] $PassThru, + # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'AutomationSysId', Mandatory)] - [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] + # [ValidateNotNullOrEmpty()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'SessionSysId')] - [Parameter(ParameterSetName = 'SessionNumber')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession, - - # Allow the results to be shown [Parameter()] - [switch] $PassThru + # [ValidateNotNullOrEmpty()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) begin {} process { - - $getSysIdParams = @{ - Table = $Table - Filter = @('number', '-eq', $number) - Properties = 'sys_id' + $getParams = @{ + Id = $Id + Property = 'sys_class_name', 'sys_id', 'number' Connection = $Connection ServiceNowSession = $ServiceNowSession } + if ( $Table ) { + $getParams.Table = $Table + } + $tableRecord = Get-ServiceNowRecord @getParams - # Use the number and table to determine the sys_id - $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id + if ( -not $tableRecord ) { + Write-Error "Record not found for Id '$Id'" + continue + } - $auth = Get-ServiceNowAuth -C $Connection -S ServiceNowSession + $auth = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession ForEach ($Object in $File) { $FileData = Get-ChildItem $Object -ErrorAction Stop @@ -114,7 +115,7 @@ Function Add-ServiceNowAttachment { # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot # $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl, $Table, $TableSysID, $FileData.Name $invokeRestMethodSplat = $auth - $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $Table, $sysId, $FileData.Name + $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $tableRecord.sys_class_name, $tableRecord.sys_id, $FileData.Name $invokeRestMethodSplat.Headers += @{'Content-Type' = $ContentType } $invokeRestMethodSplat.UseBasicParsing = $true $invokeRestMethodSplat += @{ @@ -122,7 +123,7 @@ Function Add-ServiceNowAttachment { InFile = $FileData.FullName } - If ($PSCmdlet.ShouldProcess("$Table $Number", 'Add attachment')) { + If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $tableRecord.sys_class_name, $tableRecord.number), ('Add attachment {0}' -f $FileData.FullName))) { Write-Verbose ($invokeRestMethodSplat | ConvertTo-Json) $response = Invoke-WebRequest @invokeRestMethodSplat From 0c43822e2638f4ec74f3636e88aabaaae6dfb959 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 8 Jul 2021 09:18:54 -0400 Subject: [PATCH 258/348] help cleanup --- .../Public/Export-ServiceNowAttachment.ps1 | 62 +++++-------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 index 12e7b53..65f885a 100644 --- a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 @@ -22,42 +22,34 @@ Function Export-ServiceNowAttachment { Adds the SysID to the file name. Intended for use when a ticket has multiple files with the same name. .EXAMPLE - Get-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' + Export-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' Save the attachment with the specified sys_id with a name of 'mynewfile.txt' .EXAMPLE - Get-ServiceNowAttachment -Number $Number -Table $Table | Get-ServiceNowAttachment + Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment Save all attachments from the ticket. Filenames will be assigned from the attachment name. .EXAMPLE - Get-ServiceNowAttachmentDetail -Number $Number -Table $Table | Get-ServiceNowAttachment -AppendNameWithSysID + Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -AppendNameWithSysID Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id. .EXAMPLE - Get-ServiceNowAttachmentDetail -Number $Number -Table $Table | Get-ServiceNowAttachment -Destination $Destination -AllowOverwrite + Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -Destination $path -AllowOverwrite Save all attachments from the ticket to the destination allowing for overwriting the destination file. #> - [CmdletBinding(DefaultParameterSetName = 'Table', SupportsShouldProcess = $true)] + [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess = $true)] Param( - [Parameter(ParameterSetName = 'Table', Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_class_name')] - [string] $Table, - - [Parameter(ParameterSetName = 'Table', Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $TableId, - - [Parameter(ParameterSetName = 'Attachment', Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('sys_id')] [string] $SysId, - [Parameter(ParameterSetName = 'Attachment', Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ValueFromPipelineByPropertyName)] [Alias('file_name')] [string] $FileName, @@ -77,7 +69,7 @@ Function Export-ServiceNowAttachment { [switch] $AppendNameWithSysId, # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] + [Parameter(ParameterSetName = 'Automation', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection, @@ -87,48 +79,28 @@ Function Export-ServiceNowAttachment { ) begin { - $authParams = Get-ServiceNowAuth -C $Connection -S ServiceNowSession + $authParams = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession } process { - # URI format: https://tenant.service-now.com/api/now/attachment/{sys_id}/file $params = $authParams.Clone() - # if table record provided, get the attachment details - if ( $PSCmdlet.ParameterSetName -eq 'Table' ) { - - $attachmentListParams = @{ - Table = $Table - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - - # determine if tableid is the number or sysid - try { - [guid] $TableId - $attachmentListParams.SysId = $TableId - } - catch { - $attachmentListParams.Number = $TableId - } - } - - $params.Uri += '/attachment/' + $SysID + '/file' + $params.Uri += '/attachment/' + $SysId + '/file' - If ($AppendNameWithSysId.IsPresent) { - $FileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($FileName), $SysID, [io.path]::GetExtension($FileName) + $thisFileName = $FileName + If ( $AppendNameWithSysId.IsPresent ) { + $thisFileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($thisFileName), $SysId, [io.path]::GetExtension($thisFileName) } - $OutFile = $Null - $OutFile = Join-Path $Destination $FileName + $outFile = Join-Path $Destination $thisFileName - If ((Test-Path $OutFile) -and -not $AllowOverwrite.IsPresent) { + If ((Test-Path $outFile) -and -not $AllowOverwrite.IsPresent) { throw ('The file ''{0}'' already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file.' -f $OutFile) } - $params.OutFile = $OutFile + $params.OutFile = $outFile - If ($PSCmdlet.ShouldProcess("SysId $SysId", "Save attachment to file $OutFile")) { + If ($PSCmdlet.ShouldProcess($outFile, "Save attachment")) { Invoke-WebRequest @params } } From e3608261e8a9a84b224abae610492a37878238ca Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 8 Jul 2021 21:00:52 -0400 Subject: [PATCH 259/348] deprecation warning, update cleanup --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 13 ++- .../Public/Get-ServiceNowRecordInterim.ps1 | 13 ++- ServiceNow/Public/Update-ServiceNowNumber.ps1 | 85 ------------------- ServiceNow/Public/Update-ServiceNowRecord.ps1 | 85 ++++++++++++++----- ServiceNow/ServiceNow.psd1 | 4 +- ServiceNow/ServiceNow.psm1 | 1 + 6 files changed, 76 insertions(+), 125 deletions(-) delete mode 100644 ServiceNow/Public/Update-ServiceNowNumber.ps1 diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 1c17ae0..dddbdbc 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -11,6 +11,12 @@ Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. You can also provide any table name ad hoc. +.PARAMETER Id + Either the record sys_id or number. + If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. + +.PARAMETER Name + .PARAMETER Property Limit the fields returned to this list @@ -121,16 +127,9 @@ function Get-ServiceNowRecord { [Parameter()] [switch] $IncludeCustomVariable, - # [Parameter(Mandatory, ParameterSetName = 'AutomationTable')] - # [Parameter(Mandatory, ParameterSetName = 'AutomationId')] - # [ValidateNotNullOrEmpty()] - # [AllowNull()] [Parameter()] [hashtable] $Connection, - # [Parameter(ParameterSetName = 'SessionTable')] - # [Parameter(ParameterSetName = 'SessionId')] - # [ValidateNotNullOrEmpty()] [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) diff --git a/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 b/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 index 7c4f10e..8ff79e4 100644 --- a/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 @@ -1,6 +1,6 @@ function Get-ServiceNowRecordInterim { [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsPaging)] + [CmdletBinding(SupportsPaging)] Param( # Machine name of the field to order by [Parameter()] @@ -30,17 +30,15 @@ function Get-ServiceNowRecordInterim { [Alias('DisplayValues')] [string] $DisplayValue = 'true', - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) Write-Warning ('{0} will be deprecated in the near future. Please use Get-ServiceNowRecord instead.' -f $PSCmdlet.MyInvocation.InvocationName) - + $table = $ServiceNowTable | Where-Object { $PSCmdlet.MyInvocation.InvocationName.ToLower().Replace('get-servicenow', '') -eq $_.ClassName.Replace(' ', '').ToLower() } $newServiceNowQuerySplat = @{ @@ -49,11 +47,10 @@ function Get-ServiceNowRecordInterim { OrderDirection = $OrderDirection MatchContains = $MatchContains } - $query = New-ServiceNowQuery @newServiceNowQuerySplat $params = @{ Table = $table.Name - Query = $query + Query = (New-ServiceNowQuery @newServiceNowQuerySplat) DisplayValue = $DisplayValue First = $PSCmdlet.PagingParameters.First Skip = $PSCmdlet.PagingParameters.Skip diff --git a/ServiceNow/Public/Update-ServiceNowNumber.ps1 b/ServiceNow/Public/Update-ServiceNowNumber.ps1 deleted file mode 100644 index 81a34b1..0000000 --- a/ServiceNow/Public/Update-ServiceNowNumber.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -Function Update-ServiceNowNumber { - <# - .SYNOPSIS - Allows for the passing of a number, instead of a sys_id, and associated table to update a ServiceNow entry. - - .DESCRIPTION - Allows for the passing of a number, instead of a sys_id, and associated table to update a ServiceNow entry. Output is suppressed and may be returned with a switch parameter. - - .EXAMPLE - Update-ServiceNowNumber -Number $Number -Table $Table -Values @{property='value'} - - Updates a ticket number with a value providing no return output. - - .EXAMPLE - Update-ServiceNowNumber -Number $Number -Table $Table -Values @{property='value'} -PassThru - - Updates a ticket number with a value providing return output. - .NOTES - - #> - - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] - - Param( - # Table containing the entry - [Parameter(Mandatory)] - [string]$Table, - - # Object number - [Parameter(Mandatory)] - [string]$Number, - - # Hashtable of values to use as the record's properties - [parameter()] - [hashtable]$Values, - - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, - - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession, - - # Switch to allow the results to be passed back - [parameter()] - [switch]$PassThru - ) - - begin {} - - process { - # Prep a splat to use the provided number to find the sys_id - $getSysIdParams = @{ - Table = $Table - Filter = @('number','-eq', $number) - Properties = 'sys_id' - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - - # Use the number and table to determine the sys_id - $sysId = Invoke-ServiceNowRestMethod @getSysIdParams | Select-Object -ExpandProperty sys_id - - $updateParams = @{ - Method = 'Patch' - Table = $Table - SysId = $sysId - Values = $Values - Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL - ServiceNowSession = $ServiceNowSession - } - If ($PSCmdlet.ShouldProcess("$Table $SysID", 'Update values')) { - $response = Invoke-ServiceNowRestMethod @updateParams - if ( $PassThru.IsPresent ) { - $response - } - } - } - - end {} -} diff --git a/ServiceNow/Public/Update-ServiceNowRecord.ps1 b/ServiceNow/Public/Update-ServiceNowRecord.ps1 index 1ae6b39..c54bf45 100644 --- a/ServiceNow/Public/Update-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRecord.ps1 @@ -1,51 +1,90 @@ function Update-ServiceNowRecord { - [CmdletBinding(DefaultParameterSetName = 'SessionSysId', SupportsShouldProcess)] + + <# + .SYNOPSIS + Update record values + .DESCRIPTION + Update one or more record values and optionally return the updated record + .EXAMPLE + PS C:\> + Explanation of what the example does + .INPUTS + Inputs (if any) + .OUTPUTS + Output (if any) + .NOTES + General notes + #> + + [CmdletBinding(SupportsShouldProcess)] + Param( # Table containing the entry we're updating - [parameter(Mandatory)] + [parameter(ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, - [Parameter(ParameterSetName = 'AutomationSysId', Mandatory, ValueFromPipelineByPropertyName)] - [Parameter(ParameterSetName = 'SessionSysId', Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $SysId, - - [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] - [Parameter(ParameterSetName = 'SessionNumber', Mandatory)] - [string] $Number, + [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Alias('sys_id', 'SysId', 'number')] + [string] $Id, # Hashtable of values to use as the record's properties - [parameter()] + [parameter(Mandatory)] [hashtable] $Values, - [Parameter(ParameterSetName = 'AutomationSysId', Mandatory)] - [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] - [ValidateNotNullOrEmpty()] - [Hashtable] $Connection, + [Parameter()] + [switch] $PassThru, - [Parameter(ParameterSetName = 'SessionSysId')] - [Parameter(ParameterSetName = 'SessionNumber')] - [ValidateNotNullOrEmpty()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession, + [Parameter()] + [Hashtable] $Connection, [Parameter()] - [switch] $PassThru + [hashtable] $ServiceNowSession = $script:ServiceNowSession ) begin {} process { + + if ( $Table -and ($Id -match '[a-zA-Z0-9]{32}') ) { + # we already have table name and sys_id, no more to do before update + $tableName = $Table + $sysId = $Id + } + else { + # get needed details, table name and sys_id, for update + $getParams = @{ + Id = $Id + Property = 'sys_class_name', 'sys_id', 'number' + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + + if ( $Table ) { + $getParams.Table = $Table + } + + $thisRecord = Get-ServiceNowRecord @getParams + + if ( $thisRecord ) { + $tableName = $thisRecord.sys_class_name + $sysId = $thisRecord.sys_id + } + else { + throw ('Record not found for Id ''{0}''' -f $Id) + } + } + $params = @{ Method = 'Patch' - Table = $Table - SysId = $SysId + Table = $tableName + SysId = $sysId Values = $Values Connection = $Connection ServiceNowSession = $ServiceNowSession } - If ($PSCmdlet.ShouldProcess("$Table $SysID", 'Update values')) { + If ($PSCmdlet.ShouldProcess("$tableName $sysId", 'Update values')) { $response = Invoke-ServiceNowRestMethod @params if ( $PassThru.IsPresent ) { $response diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 0ac6c02..dfbd8f1 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -59,12 +59,12 @@ FormatsToProcess = @('ServiceNow.format.ps1xml') NestedModules = @() # Functions to export from this module - FunctionsToExport = @('Get-ServiceNowRecordInterim','New-ServiceNowConfigurationItem','Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Export-ServiceNowAttachment','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowRecord','Remove-ServiceNowAttachment','Remove-ServiceNowAuth','Remove-ServiceNowRecord','Set-ServiceNowAuth','Test-ServiceNowAuthIsSet','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowNumber','Update-ServiceNowRequestItem','Update-ServiceNowRecord') + FunctionsToExport = @('Get-ServiceNowRecordInterim','New-ServiceNowConfigurationItem','Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Export-ServiceNowAttachment','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowRecord','Remove-ServiceNowAttachment','Remove-ServiceNowRecord','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowRequestedItem','Update-ServiceNowRecord') # Variables to export from this module VariablesToExport = @('ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable') - AliasesToExport = @('gsnr','Get-ServiceNowIncident','Get-ServiceNowChangeRequest', 'Get-ServiceNowConfigurationItem', 'Get-ServiceNowRequest', 'Get-ServiceNowRequestedItem', 'Get-ServiceNowUser', 'Get-ServiceNowUserGroup') + AliasesToExport = @('gsnr','Get-ServiceNowIncident','Get-ServiceNowChangeRequest', 'Get-ServiceNowConfigurationItem', 'Get-ServiceNowRequest', 'Get-ServiceNowRequestedItem', 'Get-ServiceNowUser', 'Get-ServiceNowUserGroup','Update-ServiceNowNumber') # List of all modules packaged with this module # ModuleList = @() diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 2a7a533..6dcb65d 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -54,6 +54,7 @@ $aliases = @{ 'Remove-ServiceNowTableEntry' = 'Remove-ServiceNowRecord' 'New-ServiceNowTableEntry' = 'New-ServiceNowRecord' 'Update-ServiceNowTableEntry' = 'Update-ServiceNowRecord' + 'Update-ServiceNowNumber' = 'Update-ServiceNowRecord' 'gsnr' = 'Get-ServiceNowRecord' } $aliases.GetEnumerator() | ForEach-Object { From 7c1f3ab8ea3334a765dac3535a58c3c8116c7fd2 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sat, 10 Jul 2021 09:55:30 -0400 Subject: [PATCH 260/348] cred-url cleanup --- .../Public/Export-ServiceNowAttachment.ps1 | 68 +++++----- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 124 +++++++++++++----- .../Public/New-ServiceNowChangeRequest.ps1 | 24 +--- ServiceNow/Public/New-ServiceNowIncident.ps1 | 20 +-- ServiceNow/Public/New-ServiceNowRecord.ps1 | 25 +--- .../Public/Remove-ServiceNowAttachment.ps1 | 22 +--- ServiceNow/Public/Remove-ServiceNowRecord.ps1 | 19 +-- .../Public/Update-ServiceNowChangeRequest.ps1 | 21 +-- .../Public/Update-ServiceNowIncident.ps1 | 20 +-- ServiceNow/Public/Update-ServiceNowRecord.ps1 | 59 ++++++--- .../Public/Update-ServiceNowRequestedItem.ps1 | 20 +-- ServiceNow/ServiceNow.format.ps1xml | 6 +- ServiceNow/config/main.json | 20 +-- 13 files changed, 206 insertions(+), 242 deletions(-) diff --git a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 index 65f885a..6bfed53 100644 --- a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 @@ -1,48 +1,49 @@ -Function Export-ServiceNowAttachment { - <# - .SYNOPSIS - Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. +<# +.SYNOPSIS +Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. + +.DESCRIPTION +Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. - .DESCRIPTION - Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. +.PARAMETER SysID +The ServiceNow sys_id of the file - .PARAMETER SysID - The ServiceNow sys_id of the file +.PARAMETER FileName +File name the file is saved as. Do not include the path. - .PARAMETER FileName - File name the file is saved as. Do not include the path. +.PARAMETER Destination +Path the file is saved to. Do not include the file name. - .PARAMETER Destination - Path the file is saved to. Do not include the file name. +.PARAMETER AllowOverwrite +Allows the function to overwrite the existing file. - .PARAMETER AllowOverwrite - Allows the function to overwrite the existing file. +.PARAMETER AppendNameWithSysID +Adds the SysID to the file name. Intended for use when a ticket has multiple files with the same name. - .PARAMETER AppendNameWithSysID - Adds the SysID to the file name. Intended for use when a ticket has multiple files with the same name. +.EXAMPLE +Export-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' - .EXAMPLE - Export-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' +Save the attachment with the specified sys_id with a name of 'mynewfile.txt' - Save the attachment with the specified sys_id with a name of 'mynewfile.txt' +.EXAMPLE +Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment - .EXAMPLE - Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment +Save all attachments from the ticket. Filenames will be assigned from the attachment name. - Save all attachments from the ticket. Filenames will be assigned from the attachment name. +.EXAMPLE +Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -AppendNameWithSysID - .EXAMPLE - Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -AppendNameWithSysID +Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id. - Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id. +.EXAMPLE +Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -Destination $path -AllowOverwrite - .EXAMPLE - Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -Destination $path -AllowOverwrite +Save all attachments from the ticket to the destination allowing for overwriting the destination file. +#> +Function Export-ServiceNowAttachment { - Save all attachments from the ticket to the destination allowing for overwriting the destination file. - #> + [CmdletBinding(SupportsShouldProcess)] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess = $true)] Param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] @@ -68,13 +69,10 @@ Function Export-ServiceNowAttachment { [parameter()] [switch] $AppendNameWithSysId, - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'Automation', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index dddbdbc..a7ba0ac 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -1,10 +1,9 @@ <# .SYNOPSIS - Retrieves records for the specified table + Retrieves records for any and all tables .DESCRIPTION - Retrieve records from any table with the option to filter, sort, and choose fields. - Given you know the table name, you shouldn't need any other 'Get-' function. + Retrieve records from any table with the option to filter, sort, choose fields, and more. Paging is supported with -First, -Skip, and -IncludeTotalCount. .PARAMETER Table @@ -15,10 +14,18 @@ Either the record sys_id or number. If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. -.PARAMETER Name +.PARAMETER ParentId + The sys_id or number of the parent record. + For example, to get catalog tasks for a requested item, provide the RITM number as ParentId. + +.PARAMETER Description + Filter results based on the 'description' field. The field will be different for each table. + For many tables it will be short_description, but, for instance, the User table will be 'Name'. + For unknown tables, the field will be 'short_description'. + The comparison performed is a 'like'. .PARAMETER Property - Limit the fields returned to this list + Return one or more specific fields .PARAMETER Filter Array or multidimensional array of fields and values to filter on. @@ -51,7 +58,19 @@ ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. .EXAMPLE - Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1'), 'or', @('short_description','-like', 'powershell') + Get-ServiceNowRecord RITM0010001 + Get a specific record by number + +.EXAMPLE + Get-ServiceNowRecord -Id RITM0010001 -Property 'short_description','sys_id' + Get specific properties for a record + +.EXAMPLE + Get-ServiceNowRecord -Table 'Catalog Task' -ParentId 'RITM0010001' + Get tasks for the parent requested item + +.EXAMPLE + Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Description 'powershell' Get incident records where state equals New or short description contains the word powershell .EXAMPLE @@ -61,7 +80,7 @@ '-group', @('state', '-eq', '2') PS > Get-ServiceNowRecord -Table incident -Filter $filter - Get incident records where state equals New and short description contains the word powershell or state equals In Progress. + Get incident records where state is New and short description contains the word powershell or state is In Progress. The first 2 filters are combined and then or'd against the last. .EXAMPLE @@ -80,6 +99,10 @@ Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -First 5 Get the first 5 change requests and retrieve custom variable info +.EXAMPLE + gsnr RITM0010001 + Get a specific record by number using the function alias + .INPUTS None @@ -106,7 +129,10 @@ function Get-ServiceNowRecord { [string] $Id, [Parameter()] - [string] $Name, + [string] $ParentId, + + [Parameter()] + [string] $Description, [Parameter()] [Alias('Fields', 'Properties')] @@ -134,52 +160,84 @@ function Get-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - # it's easier this way to pass everything to invoke-servicenowrestmethod given paging params, etc - $invokeParams = $PSBoundParameters - $invokeParams.Remove('IncludeCustomVariable') | Out-Null - $invokeParams.Remove('Id') | Out-Null - $invokeParams.Remove('Name') | Out-Null + $invokeParams = @{ + Table = $Table + Filter = $Filter + Property = $Property + Sort = $Sort + DisplayValue = $DisplayValue + First = $PSCmdlet.PagingParameters.First + Skip = $PSCmdlet.PagingParameters.Skip + IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } if ( $Id ) { if ( $Id -match '[a-zA-Z0-9]{32}' ) { - if ( $PSCmdlet.ParameterSetName -like '*Id' ) { - throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567.' + if ( $PSCmdlet.ParameterSetName -eq 'Id' ) { + throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' } $idFilter = @('sys_id', '-eq', $Id) } else { - if ( $PSCmdlet.ParameterSetName -like '*Id' ) { + if ( $PSCmdlet.ParameterSetName -eq 'Id' ) { # get table name from prefix if only Id was provided - $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $Id.ToLower().StartsWith($_.NumberPrefix) } | Select-Object -ExpandProperty Name + $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $Id.ToLower().StartsWith($_.NumberPrefix) } if ( $thisTable ) { - $invokeParams.Table = $thisTable + $invokeParams.Table = $thisTable.Name } else { - throw ('Prefix not found for Id ''{0}''. Known prefixes are {1}.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) } } $idFilter = @('number', '-eq', $Id) } - if ( $invokeParmas.Filter ) { + if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter } else { $invokeParams.Filter = $idFilter } } + else { + # table name was provided, get the config entry if there is one + $thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } + } - if ( $Name ) { - # determine the field we should compare for 'name' and add the filter - $thisNameField = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } | Select-Object -ExpandProperty TableNameField - if ( $thisNameField ) { - if ( $invokeParmas.Filter ) { - $invokeParams.Filter = $invokeParams.Filter, 'and', @($thisNameField, '-like', $Name) - } - else { - $invokeParams.Filter = @($thisNameField, '-like', $Name) - } + if ( $ParentId ) { + if ( $ParentId -match '[a-zA-Z0-9]{32}' ) { + $parentIdFilter = @('parent.sys_id', '-eq', $ParentId) + } + else { + $parentIdFilter = @('parent.number', '-eq', $ParentId) + } + + if ( $invokeParams.Filter ) { + $invokeParams.Filter = $invokeParams.Filter, 'and', $parentIdFilter + } + else { + $invokeParams.Filter = $parentIdFilter + } + } + + if ( $Description ) { + # determine the field we should compare for 'description' and add the filter + if ( $thisTable ) { + $nameFilter = @($thisTable.DescriptionField, '-like', $Description) + } + else { + Write-Warning ('We do not have a description field for table ''{0}''; short_description will be used' -f $Table) + $nameFilter = @('short_description', '-like', $Description) + } + + if ( $invokeParams.Filter ) { + $invokeParams.Filter = $invokeParams.Filter, 'and', $nameFilter + } + else { + $invokeParams.Filter = $nameFilter } } @@ -193,6 +251,7 @@ function Get-ServiceNowRecord { } } + # should use Get-ServiceNowAttachment, but put this here for ease of access if ( $Table -eq 'attachment' ) { $invokeParams.Remove('Table') | Out-Null $invokeParams.UriLeaf = '/attachment' @@ -246,9 +305,8 @@ function Get-ServiceNowRecord { # format the results if ( -not $Property ) { - $type = $script:ServiceNowTable | Where-Object { $_.Name -eq $Table -or $_.ClassName -eq $Table } | Select-Object -ExpandProperty Type - if ($type) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } + if ($thisTable.Type) { + $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $thisTable.Type) } } } $result diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index 8f3027f..10552d4 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -33,12 +33,6 @@ function New-ServiceNowChangeRequest { .PARAMETER CustomFields Custom fields as hashtable - .PARAMETER ServiceNowCredential - Credential used to authenticate to ServiceNow - - .PARAMETER ServiceNowURL - The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance @@ -73,7 +67,7 @@ function New-ServiceNowChangeRequest { New-ServiceNowChangeRequest @newServiceNowChangeRequestSplat #> - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess)] Param( [parameter(Mandatory)] @@ -103,20 +97,10 @@ function New-ServiceNowChangeRequest { [parameter()] [hashtable]$CustomFields, - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [PSCredential]$ServiceNowCredential, - - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, - - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, + [Parameter()] + [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, [Parameter()] diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index 597fb52..ee24674 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -28,7 +28,7 @@ Generate an Incident by "Splatting" all fields used in the 1st example plus some #> function New-ServiceNowIncident { - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess)] Param( @@ -69,24 +69,10 @@ function New-ServiceNowIncident { [Alias('CustomFields')] [hashtable] $CustomField, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ServiceNowURL, - - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, [Parameter()] diff --git a/ServiceNow/Public/New-ServiceNowRecord.ps1 b/ServiceNow/Public/New-ServiceNowRecord.ps1 index 7d1a551..fd946fb 100644 --- a/ServiceNow/Public/New-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/New-ServiceNowRecord.ps1 @@ -11,15 +11,15 @@ .PARAMETER Values Hashtable with all the key/value pairs for the new record +.PARAMETER PassThru + If provided, the new record will be returned + .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance .PARAMETER ServiceNowSession ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. -.PARAMETER PassThru - If provided, the new record will be returned - .EXAMPLE New-ServiceNowRecord -Table incident -Values @{'Caller'='me';'short_description'='my issue'} Create a new record in the incident table @@ -32,7 +32,7 @@ #> function New-ServiceNowRecord { - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess)] Param ( @@ -44,23 +44,10 @@ function New-ServiceNowRecord { [parameter(Mandatory)] [hashtable] $Values, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [PSCredential] $ServiceNowCredential, - - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ServiceNowURL, - - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, [Parameter()] diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index 1525229..46cf1b7 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -24,33 +24,17 @@ Function Remove-ServiceNowAttachment { #> - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess, ConfirmImpact = 'High')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] Param( # Attachment sys_id [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id')] [string] $SysId, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateScript( { $_ | Test-ServiceNowURL })] - [ValidateNotNullOrEmpty()] - [Alias('Url')] - [string] $ServiceNowURL, - - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) diff --git a/ServiceNow/Public/Remove-ServiceNowRecord.ps1 b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 index 966c292..ffd5cf2 100644 --- a/ServiceNow/Public/Remove-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 @@ -1,5 +1,5 @@ function Remove-ServiceNowRecord { - [CmdletBinding(DefaultParameterSetName = 'Session', ConfirmImpact = 'High')] + [CmdletBinding(ConfirmImpact = 'High')] Param( # Table containing the entry we're deleting [parameter(Mandatory, ValueFromPipelineByPropertyName)] @@ -11,23 +11,10 @@ function Remove-ServiceNowRecord { [Alias('sys_id')] [string] $SysId, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [PSCredential] $ServiceNowCredential, - - # The URL for the ServiceNow instance being used - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ServiceNowURL, - - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) diff --git a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 index c49813f..e69c767 100644 --- a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 @@ -4,7 +4,7 @@ #> function Update-ServiceNowChangeRequest { - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess)] Param( # sys_id of the caller of the incident (use Get-ServiceNowUser to retrieve this) @@ -16,23 +16,10 @@ function Update-ServiceNowChangeRequest { [parameter(Mandatory)] [hashtable]$Values, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [PSCredential]$ServiceNowCredential, - - # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string]$ServiceNowURL, - - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] - [Hashtable]$Connection, + [Parameter()] + [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, [Parameter()] diff --git a/ServiceNow/Public/Update-ServiceNowIncident.ps1 b/ServiceNow/Public/Update-ServiceNowIncident.ps1 index b936992..f949ff8 100644 --- a/ServiceNow/Public/Update-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Update-ServiceNowIncident.ps1 @@ -1,6 +1,6 @@ function Update-ServiceNowIncident { - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess)] Param ( # sys_id of the caller of the incident (use Get-ServiceNowUser to retrieve this) @@ -12,24 +12,10 @@ function Update-ServiceNowIncident { [parameter(Mandatory)] [hashtable] $Values, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ServiceNowURL, - - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, [Parameter()] diff --git a/ServiceNow/Public/Update-ServiceNowRecord.ps1 b/ServiceNow/Public/Update-ServiceNowRecord.ps1 index c54bf45..d2ca623 100644 --- a/ServiceNow/Public/Update-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRecord.ps1 @@ -1,25 +1,46 @@ -function Update-ServiceNowRecord { +<# +.SYNOPSIS + Update record values + +.DESCRIPTION + Update one or more record values and optionally return the updated record + +.PARAMETER Table + Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. + You can also provide any table name ad hoc. + +.PARAMETER Id + Either the record sys_id or number. + If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. + +.PARAMETER Values + Hashtable with all the field/value pairs for the updated record - <# - .SYNOPSIS - Update record values - .DESCRIPTION - Update one or more record values and optionally return the updated record - .EXAMPLE - PS C:\> - Explanation of what the example does - .INPUTS - Inputs (if any) - .OUTPUTS - Output (if any) - .NOTES - General notes - #> +.PARAMETER PassThru + If provided, the updated record will be returned + +.PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + +.PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. + +.EXAMPLE + Update-ServiceNowRecord -Table incident -Id 'INC0010001' -Values @{State = 'Closed'} + Close an incident record + +.INPUTS + Table, Id + +.OUTPUTS + PSCustomObject, if PassThru is provided +#> + +function Update-ServiceNowRecord { [CmdletBinding(SupportsShouldProcess)] Param( - # Table containing the entry we're updating [parameter(ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, @@ -28,7 +49,6 @@ function Update-ServiceNowRecord { [Alias('sys_id', 'SysId', 'number')] [string] $Id, - # Hashtable of values to use as the record's properties [parameter(Mandatory)] [hashtable] $Values, @@ -71,7 +91,8 @@ function Update-ServiceNowRecord { $sysId = $thisRecord.sys_id } else { - throw ('Record not found for Id ''{0}''' -f $Id) + Write-Error ('Record not found for Id ''{0}''' -f $Id) + continue } } diff --git a/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 b/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 index 01f30c8..edc6c2b 100644 --- a/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 @@ -21,7 +21,7 @@ function Update-ServiceNowRequestItem { #> [OutputType([void], [System.Management.Automation.PSCustomObject])] - [CmdletBinding(DefaultParameterSetName = 'Session', SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess)] Param ( # sys_id of the ticket to update @@ -33,24 +33,10 @@ function Update-ServiceNowRequestItem { [Parameter(Mandatory)] [hashtable] $Values, - # Credential used to authenticate to ServiceNow - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [Alias('ServiceNowCredential')] - [PSCredential] $Credential, - - # The URL for the ServiceNow instance being used (eg: instancename.service-now.com) - [Parameter(ParameterSetName = 'SpecifyConnectionFields', Mandatory)] - [ValidateNotNullOrEmpty()] - [string] $ServiceNowURL, - - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] - [ValidateNotNullOrEmpty()] + [Parameter()] [Hashtable] $Connection, - [Parameter(ParameterSetName = 'Session')] - [ValidateNotNullOrEmpty()] + [Parameter()] [hashtable] $ServiceNowSession = $script:ServiceNowSession, [Parameter()] diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index 7e6b199..bb6a216 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -131,9 +131,9 @@ - ServiceNow.RequestItem + ServiceNow.RequestedItem - ServiceNow.RequestItem + ServiceNow.RequestedItem @@ -147,7 +147,7 @@ - 8 + 12 diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 0faf6a8..ca89fa0 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -5,60 +5,60 @@ "ClassName": "Incident", "Type": "ServiceNow.Incident", "NumberPrefix": "inc", - "TableNameField": "short_description" + "DescriptionField": "short_description" }, { "Name": "change_request", "ClassName": "Change Request", "Type": "ServiceNow.ChangeRequest", "NumberPrefix": "chg", - "TableNameField": "short_description" + "DescriptionField": "short_description" }, { "Name": "cmdb_ci", "ClassName": "Configuration Item", "Type": "ServiceNow.ConfigurationItem", - "TableNameField": "name" + "DescriptionField": "name" }, { "Name": "sc_request", "ClassName": "Request", "Type": "ServiceNow.Request", "NumberPrefix": "req", - "TableNameField": "short_description" + "DescriptionField": "short_description" }, { "Name": "sc_req_item", "ClassName": "Requested Item", - "Type": "ServiceNow.RequestItem", + "Type": "ServiceNow.RequestedItem", "NumberPrefix": "ritm", - "TableNameField": "short_description" + "DescriptionField": "short_description" }, { "Name": "sys_user", "ClassName": "User", "Type": "ServiceNow.UserAndUserGroup", - "TableNameField": "name" + "DescriptionField": "name" }, { "Name": "sys_user_group", "ClassName": "User Group", "Type": "ServiceNow.UserAndUserGroup", - "TableNameField": "name" + "DescriptionField": "name" }, { "Name": "sc_task", "ClassName": "Catalog Task", "Type": "ServiceNow.CatalogTask", "NumberPrefix": "sctask", - "TableNameField": "short_description" + "DescriptionField": "short_description" }, { "Name": "change_task", "ClassName": "Change Task", "Type": "ServiceNow.ChangeTask", "NumberPrefix": "ctask", - "TableNameField": "short_description" + "DescriptionField": "short_description" } ], "FilterOperators": [ From c20f2f5e2142f3f1b115382a2193e8d17d26dbc6 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 12 Jul 2021 16:04:59 -0400 Subject: [PATCH 261/348] old cred cleanup, help updates --- CHANGELOG.md | 22 +++++++++++++++++++ .../Public/Add-ServiceNowAttachment.ps1 | 4 ---- .../Public/New-ServiceNowChangeRequest.ps1 | 2 -- ServiceNow/Public/New-ServiceNowIncident.ps1 | 2 -- .../Public/Remove-ServiceNowAttachment.ps1 | 2 -- ServiceNow/Public/Remove-ServiceNowRecord.ps1 | 3 +-- .../Public/Update-ServiceNowChangeRequest.ps1 | 2 -- .../Public/Update-ServiceNowIncident.ps1 | 2 -- .../Public/Update-ServiceNowRequestedItem.ps1 | 2 -- ServiceNow/ServiceNow.psm1 | 1 + 10 files changed, 24 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 973508e..597a35d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +## 3.0 +- This is a big update and one that preps us for the future (in my opinion and hopefully :smile:). I've tried to limit the breaking changes, but there are some at the bottom of the list. As always, any feedback is truly appreciated. +- New functionality in `Get-ServiceNowRecord` + - Add `Id` property to easily retrieve a record by either number or sysid. + - Add `ParentId` property to easily retrieve records based on the parent number or sysid. For example, to retrieve catalog tasks associated with a requested item execute `Get-ServiceNowRecord -ParentId RITM01234567`. + - Add `Description` property to retrieve records based on a table specific description field. For many tables this field will be short_description, but will be different for others. For example, when performing this against the 'User' table, the description field is 'Name'. + - Add ability to provide a known prefixed `Id` without providing `Table`, `Get-ServiceNowRecord -Id inc0010001`. To see the list of known prefixes, execute `$ServiceNowTable.NumberPrefix` after importing the module. + - Add alias `gsnr`. With the above change, a Get can be as simple as `gsnr inc0010001`. +- Add autocomplete for `Table` parameter in `Add-ServiceNowAttachment` and `Get-ServiceNowAttachment`. +- Add `Id` parameter to `Add-ServiceNowAttachment` and `Update-ServiceNowRecord` which accepts either number or sysid. Just as with `Get-ServiceNowRecord` you can now provide just `Id` if it has a known prefix. +- Add ability to `Get-ServiceNowAttachment` to get attachments either via associated record or directly from the attachments table when you want to search all attachments. +- Add advanced filtering and sorting functionality to `Get-ServiceNowAttachment` which can be really useful when searching across the attachments table. +- Convert access and refresh tokens in $ServiceNowSession from plain text to a credential for added security. +- Pipeline enhancements added in many places. +- Add Change Task and Attachments to formats. +- `Update-ServiceNowNumber` has been deprecated and the functionality has been added to `Update-ServiceNowRecord`. An alias has also been added so existing scripts do not break. +- Prep for removal of all `Get-` functions except for `Get-ServiceNowRecord` and `Get-ServiceNowAttachment`. Table specific Get functions have been deprecated. `Get-ServiceNowRecordInterim` has been created and all table specific Get functions have been aliased so existing scripts do not break. Please start to migrate to `Get-ServiceNowRecord` as these functions will all be deprecated in the near future. +- As communicated in v2.0, authentication cleanup has occurred. This involves removal of Credential/Url authentication in each function in favor of `ServiceNowSession`. You can still authenticate with Credential/Url, but must use `New-ServiceNowSession`. `Set-ServiceNowAuth`, `Remove-ServiceNowAuth`, and `Test-ServiceNowAuthIsSet` have been deprecated. +- ***Breaking change:*** rename `Get-ServiceNowAttachmentDetail` to `Get-ServiceNowAttachment`. +- ***Breaking change:*** rename `Get-ServiceNowAttachment` to `Export-ServiceNowAttachment`. +- ***Breaking change:*** `Get-ServiceNowTable` and `Get-ServiceNowTableEntry` have been deprecated. Use `Get-ServiceNowRecord`. + ## 2.4.2 - Fix [#141](https://github.com/Snow-Shell/servicenow-powershell/issues/141), add `UseBasicParsing` to all API calls to keep AA from failing when IE hasn't been initialized diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 67e9f28..874844a 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -51,10 +51,6 @@ Function Add-ServiceNowAttachment { [Alias('sys_id', 'SysId', 'number')] [string] $Id, - # [Parameter(ParameterSetName = 'AutomationNumber', Mandatory)] - # [Parameter(ParameterSetName = 'SessionNumber', Mandatory)] - # [string] $Number, - [Parameter(Mandatory)] [ValidateScript( { Test-Path $_ diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index 10552d4..c609921 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -156,8 +156,6 @@ function New-ServiceNowChangeRequest { Table = 'change_request' Values = $TableEntryValues Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index ee24674..adf12b1 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -128,8 +128,6 @@ function New-ServiceNowIncident { Table = 'incident' Values = $TableEntryValues Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } diff --git a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 index 46cf1b7..f1246e2 100644 --- a/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowAttachment.ps1 @@ -46,8 +46,6 @@ Function Remove-ServiceNowAttachment { Method = 'Delete' UriLeaf = "/attachment/$SysId" Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } diff --git a/ServiceNow/Public/Remove-ServiceNowRecord.ps1 b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 index ffd5cf2..ee0db95 100644 --- a/ServiceNow/Public/Remove-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 @@ -23,9 +23,8 @@ function Remove-ServiceNowRecord { Table = $Table SysId = $SysId Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } + Invoke-ServiceNowRestMethod @params } diff --git a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 index e69c767..3b83b1d 100644 --- a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 @@ -35,8 +35,6 @@ function Update-ServiceNowChangeRequest { SysId = $SysId Values = $Values Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } diff --git a/ServiceNow/Public/Update-ServiceNowIncident.ps1 b/ServiceNow/Public/Update-ServiceNowIncident.ps1 index f949ff8..dd2fe0b 100644 --- a/ServiceNow/Public/Update-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/Update-ServiceNowIncident.ps1 @@ -31,8 +31,6 @@ function Update-ServiceNowIncident { SysId = $SysId Values = $Values Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } diff --git a/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 b/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 index edc6c2b..caa80ff 100644 --- a/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 @@ -53,8 +53,6 @@ function Update-ServiceNowRequestItem { SysId = $SysId Values = $Values Connection = $Connection - Credential = $Credential - ServiceNowUrl = $ServiceNowURL ServiceNowSession = $ServiceNowSession } diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 6dcb65d..5be9314 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -19,6 +19,7 @@ $tableArgCompleterSb = { @( 'Get-ServiceNowRecord', 'Get-ServiceNowAttachment' + 'Add-ServiceNowAttachment' ) | ForEach-Object { Register-ArgumentCompleter -CommandName $_ -ParameterName 'Table' -ScriptBlock $tableArgCompleterSb } From 99841fbc5653aefcb378b9043642767db5018972 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 12 Jul 2021 19:51:36 -0400 Subject: [PATCH 262/348] version update --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index dfbd8f1..ac97647 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '2.4.2' +ModuleVersion = '3.0.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 95c295e00d8ba9889693bba5bb770201e0b031a2 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 12 Jul 2021 19:53:06 -0400 Subject: [PATCH 263/348] changelog update --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 597a35d..eac28d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,4 @@ ## 3.0 -- This is a big update and one that preps us for the future (in my opinion and hopefully :smile:). I've tried to limit the breaking changes, but there are some at the bottom of the list. As always, any feedback is truly appreciated. - New functionality in `Get-ServiceNowRecord` - Add `Id` property to easily retrieve a record by either number or sysid. - Add `ParentId` property to easily retrieve records based on the parent number or sysid. For example, to retrieve catalog tasks associated with a requested item execute `Get-ServiceNowRecord -ParentId RITM01234567`. From ffba5b88a8c963d7234de8194c098b9cceadf96e Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 13 Jul 2021 12:13:18 -0400 Subject: [PATCH 264/348] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eac28d0..4c6e506 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## 3.0 - New functionality in `Get-ServiceNowRecord` - Add `Id` property to easily retrieve a record by either number or sysid. - - Add `ParentId` property to easily retrieve records based on the parent number or sysid. For example, to retrieve catalog tasks associated with a requested item execute `Get-ServiceNowRecord -ParentId RITM01234567`. + - Add `ParentId` property to easily retrieve records based on the parent number or sysid. For example, to retrieve catalog tasks associated with a requested item execute `Get-ServiceNowRecord -Table 'Catalog Task' -ParentId RITM01234567`. - Add `Description` property to retrieve records based on a table specific description field. For many tables this field will be short_description, but will be different for others. For example, when performing this against the 'User' table, the description field is 'Name'. - Add ability to provide a known prefixed `Id` without providing `Table`, `Get-ServiceNowRecord -Id inc0010001`. To see the list of known prefixes, execute `$ServiceNowTable.NumberPrefix` after importing the module. - Add alias `gsnr`. With the above change, a Get can be as simple as `gsnr inc0010001`. From c4079d965f2c38c596b0c986d06d8923f15000cf Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 16 Jul 2021 19:42:00 -0400 Subject: [PATCH 265/348] fix code paths to auto determine table --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 49 ++++++++++++---------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index a7ba0ac..ad05023 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -161,7 +161,6 @@ function Get-ServiceNowRecord { ) $invokeParams = @{ - Table = $Table Filter = $Filter Property = $Property Sort = $Sort @@ -173,40 +172,51 @@ function Get-ServiceNowRecord { ServiceNowSession = $ServiceNowSession } + if ( $Table ) { + $thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } + if ( -not $thisTable ) { + # we aren't aware of this table, create default config + $thisTable = @{ + Name = $Table + ClassName = $null + Type = $null + NumberPrefix = $null + DescriptionField = $null + } + } + } + if ( $Id ) { if ( $Id -match '[a-zA-Z0-9]{32}' ) { - if ( $PSCmdlet.ParameterSetName -eq 'Id' ) { + if ( -not $thisTable ) { throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' } - + $idFilter = @('sys_id', '-eq', $Id) } else { - if ( $PSCmdlet.ParameterSetName -eq 'Id' ) { + if ( -not $thisTable ) { # get table name from prefix if only Id was provided $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $Id.ToLower().StartsWith($_.NumberPrefix) } - if ( $thisTable ) { - $invokeParams.Table = $thisTable.Name - } - else { + if ( -not $thisTable ) { throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) } } $idFilter = @('number', '-eq', $Id) } - + if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter } else { $invokeParams.Filter = $idFilter } - } - else { - # table name was provided, get the config entry if there is one - $thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } + } + # we have the table, update the params + $invokeParams.Table = $thisTable.Name + if ( $ParentId ) { if ( $ParentId -match '[a-zA-Z0-9]{32}' ) { $parentIdFilter = @('parent.sys_id', '-eq', $ParentId) @@ -225,19 +235,16 @@ function Get-ServiceNowRecord { if ( $Description ) { # determine the field we should compare for 'description' and add the filter - if ( $thisTable ) { - $nameFilter = @($thisTable.DescriptionField, '-like', $Description) - } - else { - Write-Warning ('We do not have a description field for table ''{0}''; short_description will be used' -f $Table) - $nameFilter = @('short_description', '-like', $Description) + if ( -not $thisTable.DescriptionField ) { + Write-Warning ('We do not have table ''{0}'' in the config; short_description will be used as the description field' -f $Table) + $thisTable.DescriptionField = 'short_description' } if ( $invokeParams.Filter ) { - $invokeParams.Filter = $invokeParams.Filter, 'and', $nameFilter + $invokeParams.Filter = $invokeParams.Filter, 'and', @($thisTable.DescriptionField, '-like', $Description) } else { - $invokeParams.Filter = $nameFilter + $invokeParams.Filter = @($thisTable.DescriptionField, '-like', $Description) } } From 2968fa301dcce4ba4608d57623f5b78170ac423d Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 20 Jul 2021 11:15:54 -0400 Subject: [PATCH 266/348] validate id params --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index ad05023..359d54e 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -125,10 +125,26 @@ function Get-ServiceNowRecord { [Parameter(ParameterSetName = 'Id', Mandatory, Position = 0)] [Parameter(ParameterSetName = 'Table')] + [ValidateScript( { + if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { + $true + } + else { + throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' + } + })] [Alias('sys_id', 'number')] [string] $Id, [Parameter()] + [ValidateScript( { + if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { + $true + } + else { + throw 'ParentId must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' + } + })] [string] $ParentId, [Parameter()] From 3d8f02fccb24710473c52a65fa9ceeff239051d4 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 20 Jul 2021 11:18:24 -0400 Subject: [PATCH 267/348] compare entire id prefix to avoid issues --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 359d54e..0615227 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -203,7 +203,7 @@ function Get-ServiceNowRecord { } if ( $Id ) { - if ( $Id -match '[a-zA-Z0-9]{32}' ) { + if ( $Id -match '^[a-zA-Z0-9]{32}$' ) { if ( -not $thisTable ) { throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' } @@ -213,7 +213,9 @@ function Get-ServiceNowRecord { else { if ( -not $thisTable ) { # get table name from prefix if only Id was provided - $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $Id.ToLower().StartsWith($_.NumberPrefix) } + $idPrefix = ($Id | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() + Write-Debug "Id prefix is $idPrefix" + $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } if ( -not $thisTable ) { throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) } @@ -234,7 +236,7 @@ function Get-ServiceNowRecord { $invokeParams.Table = $thisTable.Name if ( $ParentId ) { - if ( $ParentId -match '[a-zA-Z0-9]{32}' ) { + if ( $ParentId -match '^[a-zA-Z0-9]{32}$' ) { $parentIdFilter = @('parent.sys_id', '-eq', $ParentId) } else { From a9428750580f4f5d43198d28030f298d96fed008 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 22 Jul 2021 14:59:09 -0400 Subject: [PATCH 268/348] add dot walk example --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 0615227..5dc5262 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -73,6 +73,10 @@ Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Description 'powershell' Get incident records where state equals New or short description contains the word powershell +.EXAMPLE + Get-ServiceNowRecord -Table incident -Filter @('assigned_to.name', '-like', 'greg') + Get incident records where the assigned to user's name contains greg + .EXAMPLE $filter = @('state', '-eq', '1'), '-and', From 6771b97f6729dbc4a6f152db0e0285c43e4731f3 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 27 Jul 2021 20:11:09 -0400 Subject: [PATCH 269/348] account for empty table class names --- ServiceNow/ServiceNow.psm1 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 5be9314..9cad2ec 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -5,13 +5,17 @@ Write-Verbose $PSScriptRoot $config = ConvertFrom-Json (Get-Content "$PSScriptRoot\Config\main.json" -Raw) $Script:ServiceNowOperator = $config.FilterOperators -$script:ServiceNowTable = $config.Tables +[System.Collections.ArrayList] $script:ServiceNowTable = $config.Tables Export-ModuleMember -Variable ServiceNowOperator, ServiceNowTable $tableArgCompleterSb = { - $ServiceNowTable.ClassName | ForEach-Object { - '''{0}''' -f $_ + $ServiceNowTable | ForEach-Object { + if ( $_.ClassName ) { + '''{0}''' -f $_.ClassName + } else { + '''{0}''' -f $_.Name + } } } @@ -55,7 +59,7 @@ $aliases = @{ 'Remove-ServiceNowTableEntry' = 'Remove-ServiceNowRecord' 'New-ServiceNowTableEntry' = 'New-ServiceNowRecord' 'Update-ServiceNowTableEntry' = 'Update-ServiceNowRecord' - 'Update-ServiceNowNumber' = 'Update-ServiceNowRecord' + 'Update-ServiceNowNumber' = 'Update-ServiceNowRecord' 'gsnr' = 'Get-ServiceNowRecord' } $aliases.GetEnumerator() | ForEach-Object { From e238197055047d1dbe1c269600cfeeceb31f9e11 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 26 Aug 2021 17:58:44 -0400 Subject: [PATCH 270/348] NumberPrefix props where needed --- ServiceNow/config/main.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index ca89fa0..8e2536e 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -38,12 +38,14 @@ "Name": "sys_user", "ClassName": "User", "Type": "ServiceNow.UserAndUserGroup", + "NumberPrefix": "", "DescriptionField": "name" }, { "Name": "sys_user_group", "ClassName": "User Group", "Type": "ServiceNow.UserAndUserGroup", + "NumberPrefix": "", "DescriptionField": "name" }, { From b6bd57269bd9b47e588a992b4ff226e039ba383b Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 26 Aug 2021 17:59:07 -0400 Subject: [PATCH 271/348] table name fix --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 27 +++++++++++---------- ServiceNow/Public/New-ServiceNowSession.ps1 | 24 +++++++++++++++++- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 5dc5262..dc9a501 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -68,7 +68,7 @@ .EXAMPLE Get-ServiceNowRecord -Table 'Catalog Task' -ParentId 'RITM0010001' Get tasks for the parent requested item - + .EXAMPLE Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Description 'powershell' Get incident records where state equals New or short description contains the word powershell @@ -106,7 +106,7 @@ .EXAMPLE gsnr RITM0010001 Get a specific record by number using the function alias - + .INPUTS None @@ -205,13 +205,13 @@ function Get-ServiceNowRecord { } } } - + if ( $Id ) { if ( $Id -match '^[a-zA-Z0-9]{32}$' ) { if ( -not $thisTable ) { throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' } - + $idFilter = @('sys_id', '-eq', $Id) } else { @@ -226,19 +226,19 @@ function Get-ServiceNowRecord { } $idFilter = @('number', '-eq', $Id) } - + if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter } else { $invokeParams.Filter = $idFilter } - + } - + # we have the table, update the params $invokeParams.Table = $thisTable.Name - + if ( $ParentId ) { if ( $ParentId -match '^[a-zA-Z0-9]{32}$' ) { $parentIdFilter = @('parent.sys_id', '-eq', $ParentId) @@ -254,11 +254,11 @@ function Get-ServiceNowRecord { $invokeParams.Filter = $parentIdFilter } } - + if ( $Description ) { # determine the field we should compare for 'description' and add the filter if ( -not $thisTable.DescriptionField ) { - Write-Warning ('We do not have table ''{0}'' in the config; short_description will be used as the description field' -f $Table) + Write-Warning ('We do not have table ''{0}'' in the config; short_description will be used as the description field' -f $thisTable.Name) $thisTable.DescriptionField = 'short_description' } @@ -281,11 +281,12 @@ function Get-ServiceNowRecord { } # should use Get-ServiceNowAttachment, but put this here for ease of access - if ( $Table -eq 'attachment' ) { + if ( $thisTable.Name -eq 'attachment' ) { + Write-Warning 'For attachments, use Get-ServiceNowAttachment' $invokeParams.Remove('Table') | Out-Null $invokeParams.UriLeaf = '/attachment' } - + $result = Invoke-ServiceNowRestMethod @invokeParams if ( $result ) { @@ -302,7 +303,7 @@ function Get-ServiceNowRecord { if ( $customVars ) { $customValueParams = @{ - Table = $Table + Table = $thisTable.Name Filter = @('sys_id', '-eq', $record.sys_id) Property = $customVars.'sc_item_option.item_option_new.name' | ForEach-Object { "variables.$_" } } diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index d134b6f..8c78712 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -153,7 +153,7 @@ function New-ServiceNowSession { $oldProgressPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' - + $response = Invoke-WebRequest @params # set the progress pref back now that done with invoke-webrequest @@ -217,4 +217,26 @@ function New-ServiceNowSession { else { $Script:ServiceNowSession = $newSession } + + Write-Verbose 'Getting table number prefixes' + $defaultTable = $ServiceNowTable + try { + $numbers = Get-ServiceNowRecord -Table 'sys_number' -Property prefix, category -First 10000 + foreach ($number in $numbers) { + if ( $number.prefix.ToLower() -notin $defaultTable.NumberPrefix ) { + $ServiceNowTable.Add( + [pscustomobject] @{ + "Name" = ($number.category.link | Select-String -Pattern '^.*\?name=(.*)$').matches.groups[1].Value + "ClassName" = $number.category.display_value + "Type" = $null + "NumberPrefix" = $number.prefix.ToLower() + "DescriptionField" = "short_description" + } + ) | Out-Null + } + } + } + catch { + Write-Verbose "Session created, but failed to populate ServiceNowTable. Prefixes beyond the default won't be available. $_" + } } From eb8d0d4048ec27dbdf7a1f4e6d7ba5a7bed119b7 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 26 Aug 2021 18:33:46 -0400 Subject: [PATCH 272/348] dont validate url on new session --- ServiceNow/Public/New-ServiceNowSession.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 8c78712..4cc72d5 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -68,7 +68,6 @@ function New-ServiceNowSession { param( [Parameter(Mandatory)] - [ValidateScript( { $_ | Test-ServiceNowURL })] [Alias('ServiceNowUrl')] [string] $Url, From 689a736bd599593381eab12e660087eeee33cd26 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 26 Aug 2021 18:39:00 -0400 Subject: [PATCH 273/348] debug messaging --- ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index c9650a6..661d5a4 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -149,6 +149,8 @@ function Invoke-ServiceNowRestMethod { $response = Invoke-WebRequest @params + Write-Debug ($response | ConvertTo-Json) + # TODO: this could use some work # checking for content is good, but at times we'll get content that's not valid # eg. html content when a dev instance is hibernating @@ -193,7 +195,7 @@ function Invoke-ServiceNowRestMethod { $end = if ( $totalRecordCount -lt $setPoint ) { $totalRecordCount } - else { + else { $setPoint } From 870a55e92ca2cba9a9be3dfe9ce08914f671f5ba Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 26 Aug 2021 19:04:21 -0400 Subject: [PATCH 274/348] release prep --- CHANGELOG.md | 4 ++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c6e506..ea7b725 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.0.1 +- Fix [#149](https://github.com/Snow-Shell/servicenow-powershell/issues/149), combination of `-Id` and `-IncludeCustomVariable` failing. Thanks @natescherer. +- Fix [#150](https://github.com/Snow-Shell/servicenow-powershell/issues/150), Test-ServiceNowURL does not account for URL with a - character. The validation was providing much value so was removed. + ## 3.0 - New functionality in `Get-ServiceNowRecord` - Add `Id` property to easily retrieve a record by either number or sysid. diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index ac97647..c4d2c03 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.0.0' +ModuleVersion = '3.0.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 7ec1351638c418a1c4fcb568e6716c7425cd37f9 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 26 Aug 2021 19:19:01 -0400 Subject: [PATCH 275/348] changelog update --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea7b725..eb9f203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 3.0.1 - Fix [#149](https://github.com/Snow-Shell/servicenow-powershell/issues/149), combination of `-Id` and `-IncludeCustomVariable` failing. Thanks @natescherer. - Fix [#150](https://github.com/Snow-Shell/servicenow-powershell/issues/150), Test-ServiceNowURL does not account for URL with a - character. The validation was providing much value so was removed. +- Getting info on all tables so we can be more intelligent/dynamic about prefixes. Querying the sys_number table and might require elevated rights. If rights aren't present, no failure will occur, this is just an added bonus for those with rights :) ## 3.0 - New functionality in `Get-ServiceNowRecord` From f8b73768472be56249b84fc56a82e8fdf3e8dbc2 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 26 Aug 2021 19:21:28 -0400 Subject: [PATCH 276/348] small update to changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb9f203..a867ffe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## 3.0.1 - Fix [#149](https://github.com/Snow-Shell/servicenow-powershell/issues/149), combination of `-Id` and `-IncludeCustomVariable` failing. Thanks @natescherer. -- Fix [#150](https://github.com/Snow-Shell/servicenow-powershell/issues/150), Test-ServiceNowURL does not account for URL with a - character. The validation was providing much value so was removed. +- Fix [#150](https://github.com/Snow-Shell/servicenow-powershell/issues/150), Test-ServiceNowURL does not account for URL with a - character. The validation wasn't providing much value so was removed. - Getting info on all tables so we can be more intelligent/dynamic about prefixes. Querying the sys_number table and might require elevated rights. If rights aren't present, no failure will occur, this is just an added bonus for those with rights :) ## 3.0 From 3dab8dacd92e984b230ac9ef3fcc8eea5e69fc23 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 9 Sep 2021 16:00:36 -0400 Subject: [PATCH 277/348] fix #152 --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 661d5a4..72f7e0e 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -147,9 +147,14 @@ function Invoke-ServiceNowRestMethod { $oldProgressPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' - $response = Invoke-WebRequest @params - - Write-Debug ($response | ConvertTo-Json) + try { + $response = Invoke-WebRequest @params + Write-Debug $response + } + catch { + $ProgressPreference = $oldProgressPreference + throw $_ + } # TODO: this could use some work # checking for content is good, but at times we'll get content that's not valid @@ -200,7 +205,13 @@ function Invoke-ServiceNowRestMethod { } Write-Verbose ('getting {0}-{1} of {2}' -f ($params.body.sysparm_offset + 1), $end, $totalRecordCount) - $response = Invoke-WebRequest @params -Verbose:$false + try { + $response = Invoke-WebRequest @params -Verbose:$false + } + catch { + $ProgressPreference = $oldProgressPreference + throw $_ + } $content = $response.content | ConvertFrom-Json if ( $content.PSobject.Properties.Name -contains "result" ) { From 638c0b09796e852d937e4a40c0f8c7a5c81eae74 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 9 Sep 2021 16:10:15 -0400 Subject: [PATCH 278/348] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a867ffe..9d81ec8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 3.0.2 +- Fix [#152](https://github.com/Snow-Shell/servicenow-powershell/issues/152), object conversion to json failing. + ## 3.0.1 - Fix [#149](https://github.com/Snow-Shell/servicenow-powershell/issues/149), combination of `-Id` and `-IncludeCustomVariable` failing. Thanks @natescherer. - Fix [#150](https://github.com/Snow-Shell/servicenow-powershell/issues/150), Test-ServiceNowURL does not account for URL with a - character. The validation wasn't providing much value so was removed. From ef50d3bde07f5da51ba2b5848d84cc0ddaf720d9 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 9 Sep 2021 16:13:30 -0400 Subject: [PATCH 279/348] update version --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index c4d2c03..24684ff 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.0.1' +ModuleVersion = '3.0.2' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 0c9d6c8f8ff00dcdbeb502a1e60f2b8e034ec985 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 21 Sep 2021 09:02:36 -0400 Subject: [PATCH 280/348] Add datetime support for querying (#154) * support datetime for querying * release prep * help updates --- CHANGELOG.md | 5 +++ ServiceNow/Public/Get-ServiceNowRecord.ps1 | 6 ++- ServiceNow/Public/New-ServiceNowQuery.ps1 | 49 +++++++++++++++++----- ServiceNow/ServiceNow.psd1 | 2 +- ServiceNow/config/main.json | 42 +++++++++++-------- 5 files changed, 72 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d81ec8..eb9a675 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.1.0 +- Add DateTime support to querying, [#68](https://github.com/Snow-Shell/servicenow-powershell/issues/68) +- Add `-between` operator +- Enhanced value validation for all operators in `New-ServiceNowQuery` which is used by `Get-ServiceNowRecord` + ## 3.0.2 - Fix [#152](https://github.com/Snow-Shell/servicenow-powershell/issues/152), object conversion to json failing. diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index dc9a501..e75f366 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -32,8 +32,6 @@ Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group'. For a complete list of comparison operators, see $script:ServiceNowOperator and use Name in your filter. See the examples. - Also, see https://docs.servicenow.com/bundle/quebec-platform-user-interface/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html - for how to represent date values with javascript. .PARAMETER Sort Array or multidimensional array of fields to sort on. @@ -87,6 +85,10 @@ Get incident records where state is New and short description contains the word powershell or state is In Progress. The first 2 filters are combined and then or'd against the last. +.EXAMPLE + Get-ServiceNowRecord -Table 'Incident' -Filter @('opened_at', '-between', (Get-Date).AddMonths(-24), (get-date).AddMonths(-12)) -IncludeTotalCount + Get all incident records that were opened between 1 and 2 years ago + .EXAMPLE Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Sort @('opened_at', 'desc'), @('state') Get incident records where state equals New and first sort by the field opened_at descending and then sort by the field state ascending diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index 9a294fc..b8bb503 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -145,31 +145,58 @@ function New-ServiceNowQuery { if ( $i -eq $filterList.Count - 1) { throw '$Filter cannot end with a join' } + + break } - 2 { - # should be a non-value operator, eg. ='' / ISEMPTY + { $_ -ne 1 } { + # perform data validation on all filters other than a join operator $thisOperator = $script:ServiceNowOperator | Where-Object { $_.Name -eq $thisFilter[1] } if ( -not $thisOperator ) { throw ('Operator ''{0}'' is not valid' -f $thisFilter[1]) } - if ( $thisOperator.RequiresValue ) { - throw ('Value not provided, {0} {1} ?' -f $thisFilter[0], $thisOperator.QueryOperator) + if ( $thisOperator.NumValues -ne $thisFilter.Count - 2 ) { + throw ('Operator ''{0}'' requires 1 field name and {1} value(s)' -f $thisFilter[1], $thisOperator.NumValues) } + } + + 2 { + # should be a non-value operator, eg. ='' / ISEMPTY '{0}{1}' -f $thisFilter[0], $thisOperator.QueryOperator + break } 3 { - # should be field operator value - $thisOperator = $script:ServiceNowOperator | Where-Object { $_.Name -eq $thisFilter[1] } - if ( -not $thisOperator ) { - throw ('Operator ''{0}'' is not valid', $thisFilter[1]) + # should be format - field operator value + + if ( $thisFilter[2] -is [DateTime] ) { + $dateGen = "'{0}','{1}'" -f $thisFilter[2].ToString('yyyy-MM-dd'), $thisFilter[2].ToString('HH:mm:ss') + '{0}{1}javascript:gs.dateGenerate({2})' -f $thisFilter[0], $thisOperator.QueryOperator, $dateGen + } + else { + '{0}{1}{2}' -f $thisFilter[0], $thisOperator.QueryOperator, $thisFilter[2] } - '{0}{1}{2}' -f $thisFilter[0], $thisOperator.QueryOperator, $thisFilter[2] + + break + } + + 4 { + # should be format - field operator value1 value2, where applicable, eg. between + + if ( $thisFilter[2] -is [DateTime] ) { + $dateGen1 = "'{0}','{1}'" -f $thisFilter[2].ToString('yyyy-MM-dd'), $thisFilter[2].ToString('HH:mm:ss') + $dateGen2 = "'{0}','{1}'" -f $thisFilter[3].ToString('yyyy-MM-dd'), $thisFilter[3].ToString('HH:mm:ss') + '{0}{1}javascript:gs.dateGenerate({2})@javascript:gs.dateGenerate({3})' -f $thisFilter[0], $thisOperator.QueryOperator, $dateGen1, $dateGen2 + } + else { + '{0}{1}{2}@{3}' -f $thisFilter[0], $thisOperator.QueryOperator, $thisFilter[2], $thisFilter[3] + } + + break } Default { - throw ('Too many items for {0}, see the help' -f $thisFilter[0]) + throw ('Too many filter items for {0}, see the help' -f $thisFilter[0]) } } } @@ -234,7 +261,7 @@ function New-ServiceNowQuery { } } - $query -join '' + ($query -join '').Trim('^') } else { diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 24684ff..eac5c32 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.0.2' +ModuleVersion = '3.1.0' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 8e2536e..8ac8cc4 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -68,109 +68,115 @@ "Name": "-eq", "QueryOperator": "=", "Description": "is equal to", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-ne", "QueryOperator": "!=", "Description": "is not equal to", - "RequiresValue": true + "NumValues": 1 }, { "Name": "=''", "QueryOperator": "ISEMPTY", "Description": "field has no value", - "RequiresValue": false + "NumValues": 0 }, { "Name": "=\"\"", "QueryOperator": "ISEMPTY", "Description": "field has no value", - "RequiresValue": false + "NumValues": 0 }, { "Name": "!=''", "QueryOperator": "ISNOTEMPTY", "Description": "field has any value", - "RequiresValue": false + "NumValues": 0 }, { "Name": "!=\"\"", "QueryOperator": "ISNOTEMPTY", "Description": "field has any value", - "RequiresValue": false + "NumValues": 0 }, { "Name": "-like", "QueryOperator": "LIKE", "Description": "value is found anywhere in field", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-notlike", "QueryOperator": "NOT LIKE", "Description": "value is not found anywhere in field", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-in", "QueryOperator": "IN", "Description": "field is populated by one of the values", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-notin", "QueryOperator": "NOT IN", "Description": "field is populated by any value except for these", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-lt", "QueryOperator": "<", "Description": "field is less than the value. can be used with dates to represent prior to the value.", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-le", "QueryOperator": "<=", "Description": "field is less than or equal to the value. can be used with dates to represent prior to or the day of the value.", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-gt", "QueryOperator": ">", "Description": "field is greater than the value. can be used with dates to represent after the value.", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-ge", "QueryOperator": ">=", "Description": "field is greater than or equal to the value. can be used with dates to represent after or the day of the value.", - "RequiresValue": true + "NumValues": 1 }, { "Name": ".startswith", "QueryOperator": "STARTSWITH", "Description": "field starts with the value", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-startswith", "QueryOperator": "STARTSWITH", "Description": "field starts with the value", - "RequiresValue": true + "NumValues": 1 }, { "Name": ".endswith", "QueryOperator": "%", "Description": "field ends with the value", - "RequiresValue": true + "NumValues": 1 }, { "Name": "-endswith", "QueryOperator": "%", "Description": "field ends with the value", - "RequiresValue": true + "NumValues": 1 + }, + { + "Name": "-between", + "QueryOperator": "BETWEEN", + "Description": "value is between 2 dates or integers", + "NumValues": 2 } ] } \ No newline at end of file From 9a64317cbe51316ec6cd93f4da45c37b398d838e Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 21 Sep 2021 09:23:46 -0400 Subject: [PATCH 281/348] update example with date --- Readme.md | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/Readme.md b/Readme.md index e7f52d2..9dab99d 100644 --- a/Readme.md +++ b/Readme.md @@ -8,18 +8,6 @@ This PowerShell module provides a series of cmdlets for interacting with the [Se **IMPORTANT:** Neither this module nor its creator are in any way affiliated with ServiceNow. -## Version 2 - -Building on the great work the community has done thus far, a lot of new updates with this release. -- Although still in the module for backward compatibility, `Set-ServiceNowAuth` is being replaced with `New-ServiceNowSession`. With this comes OAuth support, removal of global variables, and much more folks have asked for. The ability to provide credentials directly to functions has been retained for this release, but will be deprecated in a future release in favor of using `New-ServiceNowSession`. -- Support for different api versions. `Set-ServiceNowAuth` will continue to use v1 of the api, but `New-ServiceNowSession` defaults to the latest. Check out the `-ApiVersion` parameter of `New-ServiceNowSession`. -- `Remove-ServiceNowAuth` has been retained for this release, but as global variables have been removed, there is no longer a need for it; it will always return `$true`. It will be removed in a future release. -- `-PassThru` added to remaining `Update-` and `New-` functions. Depending on your code, this may be a ***breaking change*** if you expected the result to be returned. -- Pipeline support added to many functions -- Standardizing on coding between all functions - -***It is recommended to use `Get-ServiceNowRecord` instead of the other 'Get' functions.*** - ## Requirements Requires PowerShell 5.1 or above. @@ -32,7 +20,7 @@ Requires authorization in your ServiceNow tenant. Due to the custom nature of S ## Usage -The ServiceNow module should be installed from the PowerShell Gallery with `install-module ServiceNow`. +The ServiceNow module should be installed from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ServiceNow) with `install-module ServiceNow`. ### Creating a new session @@ -61,7 +49,7 @@ All examples below assume a new session has already been created. ### Getting incidents opened in the last 30 days ```PowerShell -$filter = @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') +$filter = @('opened_at', '-ge', (Get-Date).AddDays(-30)) Get-ServiceNowRecord -Table incident -Filter $filter ``` @@ -95,10 +83,6 @@ The module can use the `Connection` parameter in conjunction with the included ` The `Connection` parameter accepts a hashtable object that requires a username, password, and ServiceNowURL. -## Tests - -This module comes with limited [Pester](https://github.com/pester/Pester/) tests for unit testing. - ## Scope & Contributing Contributions are gratefully received, so please feel free to submit a pull request with additional features or amendments. From 8b0517065fb6e81724e3d72b89b045fd59990305 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 28 Sep 2021 12:28:50 -0400 Subject: [PATCH 282/348] add note that SN API doesn't support SSO --- Readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Readme.md b/Readme.md index 9dab99d..4ba2e33 100644 --- a/Readme.md +++ b/Readme.md @@ -44,6 +44,7 @@ $params @{ } New-ServiceNowSession @params ``` +**Note: ServiceNow's API does not support SSO** All examples below assume a new session has already been created. From 9a84e9a45cd0e20c603ae155e26bd3b51369cdfd Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 6 Oct 2021 13:42:52 -0400 Subject: [PATCH 283/348] Fix failure on successful record removal (#159) * don't fail on 204 with delete * make get all tables optional * fix pipelining * release prep * changelog update --- CHANGELOG.md | 5 +++ .../Private/Invoke-ServiceNowRestMethod.ps1 | 41 +++++++++++------ ServiceNow/Public/New-ServiceNowSession.ps1 | 44 +++++++++++-------- ServiceNow/Public/Remove-ServiceNowRecord.ps1 | 26 +++++++---- ServiceNow/ServiceNow.psd1 | 2 +- 5 files changed, 77 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb9a675..6e45298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.1.1 +- Fix [#158](https://github.com/Snow-Shell/servicenow-powershell/issues/158), failure on successful record deletion +- Move table details retrieval in `New-ServiceNowSession` to be switch operated, `-GetAllTable` and reduce function time +- Fix pipelining in `Remove-ServiceNowRecord` + ## 3.1.0 - Add DateTime support to querying, [#68](https://github.com/Snow-Shell/servicenow-powershell/issues/68) - Add `-between` operator diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 72f7e0e..f261116 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -156,22 +156,32 @@ function Invoke-ServiceNowRestMethod { throw $_ } - # TODO: this could use some work - # checking for content is good, but at times we'll get content that's not valid - # eg. html content when a dev instance is hibernating - if ( $response.Content ) { - $content = $response.content | ConvertFrom-Json - if ( $content.PSobject.Properties.Name -contains "result" ) { - $records = @($content | Select-Object -ExpandProperty result) + # validate response + switch ($Method) { + 'Delete' { + if ( $response.StatusCode -ne 204 ) { + throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) + } } - else { - $records = @($content) + Default { + # TODO: this could use some work + # checking for content is good, but at times we'll get content that's not valid + # eg. html content when a dev instance is hibernating + if ( $response.Content ) { + $content = $response.content | ConvertFrom-Json + if ( $content.PSobject.Properties.Name -contains "result" ) { + $records = @($content | Select-Object -ExpandProperty result) + } + else { + $records = @($content) + } + } + else { + # invoke-webrequest didn't throw an error per se, but we didn't get content back either + throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) + } } } - else { - # invoke-webrequest didn't throw an error per se, but we didn't get content back either - throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) - } $totalRecordCount = 0 if ( $response.Headers.'X-Total-Count' ) { @@ -187,7 +197,10 @@ function Invoke-ServiceNowRestMethod { # if option to get all records was provided, loop and get them all if ( $PSCmdlet.PagingParameters.IncludeTotalCount.IsPresent ) { - Write-Warning "Getting $($totalRecordCount - $PSCmdlet.PagingParameters.Skip) records, this could take a while..." + $retrieveRecordCount = $totalRecordCount - $PSCmdlet.PagingParameters.Skip + if ( $retrieveRecordCount -ne 0 ) { + Write-Warning "Getting $retrieveRecordCount records..." + } $setPoint = $params.body.sysparm_offset + $params.body.sysparm_limit diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 4cc72d5..eec3cc6 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -29,6 +29,9 @@ Credential of user who can access Proxy. If not provided, the current user will .PARAMETER ApiVersion Specific API version to use. The default is the latest. +.PARAMETER GetAllTable +Populate $ServiceNowTable with data from all tables the user has access to + .PARAMETER PassThru Provide the resulting session object to the pipeline as opposed to setting as a script scoped variable to be used by default for other calls. This is useful if you want to have multiple sessions with different api versions, credentials, etc. @@ -99,6 +102,9 @@ function New-ServiceNowSession { [Parameter()] [int] $ApiVersion, + [Parameter()] + [switch] $GetAllTable, + [Parameter()] [switch] $PassThru ) @@ -217,25 +223,27 @@ function New-ServiceNowSession { $Script:ServiceNowSession = $newSession } - Write-Verbose 'Getting table number prefixes' - $defaultTable = $ServiceNowTable - try { - $numbers = Get-ServiceNowRecord -Table 'sys_number' -Property prefix, category -First 10000 - foreach ($number in $numbers) { - if ( $number.prefix.ToLower() -notin $defaultTable.NumberPrefix ) { - $ServiceNowTable.Add( - [pscustomobject] @{ - "Name" = ($number.category.link | Select-String -Pattern '^.*\?name=(.*)$').matches.groups[1].Value - "ClassName" = $number.category.display_value - "Type" = $null - "NumberPrefix" = $number.prefix.ToLower() - "DescriptionField" = "short_description" - } - ) | Out-Null + if ( $GetAllTable.IsPresent ) { + Write-Verbose 'Getting table number prefixes' + $defaultTable = $ServiceNowTable + try { + $numbers = Get-ServiceNowRecord -Table 'sys_number' -Property prefix, category -First 10000 -IncludeTotalCount + foreach ($number in $numbers) { + if ( $number.prefix.ToLower() -notin $defaultTable.NumberPrefix ) { + $ServiceNowTable.Add( + [pscustomobject] @{ + "Name" = ($number.category.link | Select-String -Pattern '^.*\?name=(.*)$').matches.groups[1].Value + "ClassName" = $number.category.display_value + "Type" = $null + "NumberPrefix" = $number.prefix.ToLower() + "DescriptionField" = "short_description" + } + ) | Out-Null + } } } - } - catch { - Write-Verbose "Session created, but failed to populate ServiceNowTable. Prefixes beyond the default won't be available. $_" + catch { + Write-Verbose "Session created, but failed to populate ServiceNowTable. Prefixes beyond the default won't be available. $_" + } } } diff --git a/ServiceNow/Public/Remove-ServiceNowRecord.ps1 b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 index ee0db95..41e9674 100644 --- a/ServiceNow/Public/Remove-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 @@ -1,13 +1,17 @@ function Remove-ServiceNowRecord { + [CmdletBinding(ConfirmImpact = 'High')] + Param( # Table containing the entry we're deleting [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] [Alias('sys_class_name')] [string] $Table, # sys_id of the entry we're deleting [parameter(Mandatory, ValueFromPipelineByPropertyName)] + [ValidateNotNullOrEmpty()] [Alias('sys_id')] [string] $SysId, @@ -18,13 +22,19 @@ function Remove-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $params = @{ - Method = 'Delete' - Table = $Table - SysId = $SysId - Connection = $Connection - ServiceNowSession = $ServiceNowSession + begin { + + } + + process { + $params = @{ + Method = 'Delete' + Table = $Table + SysId = $SysId + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + + Invoke-ServiceNowRestMethod @params } - - Invoke-ServiceNowRestMethod @params } diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index eac5c32..acce4f3 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.0' +ModuleVersion = '3.1.1' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From c3f1ab1aab8d05eb6138285764cab66aab07636d Mon Sep 17 00:00:00 2001 From: Nate Scherer <376408+natescherer@users.noreply.github.com> Date: Wed, 27 Oct 2021 09:28:01 -0400 Subject: [PATCH 284/348] Add-ServiceNowAttachment: Use table name from param (if present) for attachment POST (#161) * Use table name from param (if present) for attachment POST * Make requested changes for PR 161 --- ServiceNow/Public/Add-ServiceNowAttachment.ps1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 874844a..1b1b30f 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -95,6 +95,13 @@ Function Add-ServiceNowAttachment { continue } + If (-not $Table) { + $tableName = $tableRecord.sys_class_name + } + else { + $tableName = $Table + } + $auth = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession ForEach ($Object in $File) { @@ -111,7 +118,7 @@ Function Add-ServiceNowAttachment { # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot # $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl, $Table, $TableSysID, $FileData.Name $invokeRestMethodSplat = $auth - $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $tableRecord.sys_class_name, $tableRecord.sys_id, $FileData.Name + $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $tableName, $tableRecord.sys_id, $FileData.Name $invokeRestMethodSplat.Headers += @{'Content-Type' = $ContentType } $invokeRestMethodSplat.UseBasicParsing = $true $invokeRestMethodSplat += @{ @@ -119,7 +126,7 @@ Function Add-ServiceNowAttachment { InFile = $FileData.FullName } - If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $tableRecord.sys_class_name, $tableRecord.number), ('Add attachment {0}' -f $FileData.FullName))) { + If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $tableName, $tableRecord.number), ('Add attachment {0}' -f $FileData.FullName))) { Write-Verbose ($invokeRestMethodSplat | ConvertTo-Json) $response = Invoke-WebRequest @invokeRestMethodSplat From ef451c36683b4788eb016ed16d35863bc036819f Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 27 Oct 2021 09:40:56 -0400 Subject: [PATCH 285/348] 3.1.2 release (#164) * Update CHANGELOG.md * Update ServiceNow.psd1 * Update CHANGELOG.md --- CHANGELOG.md | 3 +++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e45298..0184b04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 3.1.2 +- Fix [#160](https://github.com/Snow-Shell/servicenow-powershell/issues/160), adding an attachment to catalog tasks not working for instances created pre-Istanbul. Thanks @natescherer! + ## 3.1.1 - Fix [#158](https://github.com/Snow-Shell/servicenow-powershell/issues/158), failure on successful record deletion - Move table details retrieval in `New-ServiceNowSession` to be switch operated, `-GetAllTable` and reduce function time diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index acce4f3..d602b71 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.1' +ModuleVersion = '3.1.2' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' From 00825a8965837a467c3bf47582beeefeaf6356c2 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sat, 27 Nov 2021 09:44:35 -0500 Subject: [PATCH 286/348] Fix 167 (#168) --- CHANGELOG.md | 3 +++ ServiceNow/ServiceNow.psd1 | 2 +- ServiceNow/ServiceNow.psm1 | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0184b04..e2161e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 3.1.3 +- Fix [#167](https://github.com/Snow-Shell/servicenow-powershell/issues/167), fix ServiceNowTable not being populated on Linux due to file name case + ## 3.1.2 - Fix [#160](https://github.com/Snow-Shell/servicenow-powershell/issues/160), adding an attachment to catalog tasks not working for instances created pre-Istanbul. Thanks @natescherer! diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index d602b71..dd8d627 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -5,7 +5,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.2' +ModuleVersion = '3.1.3' # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 9cad2ec..5354f3e 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -3,7 +3,7 @@ param() Write-Verbose $PSScriptRoot -$config = ConvertFrom-Json (Get-Content "$PSScriptRoot\Config\main.json" -Raw) +$config = ConvertFrom-Json (Get-Content "$PSScriptRoot\config\main.json" -Raw) $Script:ServiceNowOperator = $config.FilterOperators [System.Collections.ArrayList] $script:ServiceNowTable = $config.Tables From 726b4efdae7b0974285d5ef54cf929f2b56ac29b Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 9 Dec 2021 10:25:50 -0500 Subject: [PATCH 287/348] fix missing = in readme code (#171) #169 --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 4ba2e33..1aa2f5f 100644 --- a/Readme.md +++ b/Readme.md @@ -28,7 +28,7 @@ Creating a new session will create a script scoped variable `$ServiceNowSession` Basic authentication with just a credential... ```PowerShell -$params @{ +$params = @{ Url = 'instance.service-now.com' Credential = $userCred } @@ -37,7 +37,7 @@ New-ServiceNowSession @params Oauth authentication with user credential as well as application/client credential. The application/client credential can be found in the System OAuth->Application Registry section of ServiceNow. ```PowerShell -$params @{ +$params = @{ Url = 'instance.service-now.com' Credential = $userCred ClientCredential = $clientCred From 1cc7e6020719cecb844c65908b7b6a8963f54573 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 13 Jan 2022 09:49:29 -0500 Subject: [PATCH 288/348] Create ci.yml --- .github/workflows/ci.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6be76d4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + +jobs: + Testing: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install PSScriptAnalyzer module + shell: pwsh + run: | + Set-PSRepository PSGallery -InstallationPolicy Trusted + Install-Module PSScriptAnalyzer -ErrorAction Stop + - name: Lint with PSScriptAnalyzer + shell: pwsh + run: | + Invoke-ScriptAnalyzer -Path . -Recurse -Outvariable issues + $issues | ConvertTo-Json -Depth 2 | Set-Content -Path '${{ github.workspace }}/pssa.json' + $errors = $issues.Where({$_.Severity -eq 'Error'}) + $warnings = $issues.Where({$_.Severity -eq 'Warning'}) + if ($errors) { + Write-Error "There were $($errors.Count) errors and $($warnings.Count) warnings total." -ErrorAction Stop + } else { + Write-Output "There were $($errors.Count) errors and $($warnings.Count) warnings total." + } + - name: Upload test results + uses: actions/upload-artifact@v2 + with: + name: pssa-results + path: ${{ github.workspace }}/pssa.json + # - name: Test with Pester + # shell: pwsh + # run: Invoke-Pester Unit.Tests.ps1 -Passthru | Export-CliXml -Path Unit.Tests.xml From 519a117a94680832278c7cebf6efb46a3ecde86b Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 13 Jan 2022 17:40:54 -0500 Subject: [PATCH 289/348] Create cd.yml --- .github/workflows/cd.yml | 55 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 .github/workflows/cd.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..662d672 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,55 @@ +name: CD + +on: workflow_dispatch + +jobs: + deployment: + runs-on: ubuntu-latest + env: + module_name: ServiceNow + steps: + - uses: actions/checkout@v2 + with: + token: ${{ secrets.CD_TOKEN }} + - name: Update psd version + shell: pwsh + run: | + $manifestPath = '${{ github.workspace }}/${{ env.module_name }}/${{ env.module_name }}.psd1' + $manifest = Import-PowerShellDataFile $manifestPath + [version]$version = $manifest.ModuleVersion + [version]$newVersion = "{0}.{1}.{2}" -f $Version.Major, $Version.Minor, ($Version.Build + 1) + Update-ModuleManifest -Path $manifestPath -ModuleVersion $newVersion + + # update-modulemanifest introduces whitepsace so get rid of it + (Get-Content $manifestPath).TrimEnd() | Set-Content $manifestPath + + "New version: $newVersion" + # set version to be used in later steps + "module_new_version=$newVersion" | Out-File -FilePath $env:GITHUB_ENV -Append + - name: Update changelog + shell: pwsh + run: | + $newVersionString = '## ${{ env.module_new_version }}' + $releaseNotes = Get-Content -Path '${{ github.workspace }}/RELEASE.md' -Raw + $changelog = Get-Content -Path '${{ github.workspace }}/CHANGELOG.md' -Raw + Set-Content -Path '${{ github.workspace }}/CHANGELOG.md' -Value ($newVersionString + "`r`n" + $releaseNotes + "`r`n`r`n" + $changelog) + - name: Update repo + run: | + git config --global user.name 'Greg Brownstein' + git config --global user.email 'greg@jagtechnical.com' + git add ${{ env.module_name }} + git add CHANGELOG.md + git status + git commit -m "Update manifest to ${{ env.module_new_version }}" + git push + - name: Create GitHub release + if: github.ref == 'refs/heads/master' + uses: softprops/action-gh-release@v1 + with: + tag_name: v${{ env.module_new_version }} + body_path: ${{ github.workspace }}/RELEASE.md + - name: Publish + if: github.ref == 'refs/heads/master' + shell: pwsh + run: | + Publish-Module -Path "${{ github.workspace }}/${{ env.module_name }}" -NuGetApiKey ${{ secrets.NUGET_KEY }} -Verbose From 8b1ff37b78f20e9dc3b8ba524817bf757dfb66e7 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 13 Jan 2022 19:22:24 -0500 Subject: [PATCH 290/348] Add email type when retrieving custom variables (#174) --- ServiceNow/Private/Get-ServiceNowAuth.ps1 | 4 +++- ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 | 2 ++ ServiceNow/Public/Get-ServiceNowRecord.ps1 | 2 +- ServiceNow/Public/New-ServiceNowQuery.ps1 | 2 +- ServiceNow/Public/New-ServiceNowSession.ps1 | 2 ++ 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ServiceNow/Private/Get-ServiceNowAuth.ps1 b/ServiceNow/Private/Get-ServiceNowAuth.ps1 index 85fb68f..124f231 100644 --- a/ServiceNow/Private/Get-ServiceNowAuth.ps1 +++ b/ServiceNow/Private/Get-ServiceNowAuth.ps1 @@ -11,6 +11,8 @@ function Get-ServiceNowAuth { [OutputType([Hashtable])] [CmdletBinding()] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'requirement of azure automation')] + Param ( [Parameter()] [Alias('C')] @@ -37,7 +39,7 @@ function Get-ServiceNowAuth { else { $hashOut.Credential = $ServiceNowSession.Credential } - + if ( $ServiceNowSession.Proxy ) { $hashOut.Proxy = $ServiceNowSession.Proxy if ( $ServiceNowSession.ProxyCredential ) { diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index f261116..026832e 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -15,6 +15,8 @@ function Invoke-ServiceNowRestMethod { [OutputType([System.Management.Automation.PSCustomObject])] [CmdletBinding(SupportsPaging)] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseBOMForUnicodeEncodedFile', '', Justification = 'issuees with *nix machines and no benefit')] + Param ( [parameter()] [ValidateSet('Get', 'Post', 'Patch', 'Delete')] diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index e75f366..d16063e 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -298,7 +298,7 @@ function Get-ServiceNowRecord { $customVarParams = @{ Table = 'sc_item_option_mtom' Property = 'sc_item_option.item_option_new.name', 'sc_item_option.item_option_new.sys_name', 'sc_item_option.item_option_new.type' - Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22') + Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22,26') First = 1000 # hopefully there isn't more custom vars than this, but we need to overwrite the default of 10 } $customVars = Get-ServiceNowRecord @customVarParams diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index b8bb503..e9403cf 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -63,7 +63,7 @@ #> function New-ServiceNowQuery { - [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', 'No state is actually changing')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'No state is actually changing')] [CmdletBinding()] [OutputType([System.String])] diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index eec3cc6..d5fd336 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -68,6 +68,8 @@ https://docs.servicenow.com/bundle/quebec-platform-administration/page/administe function New-ServiceNowSession { [CmdletBinding(DefaultParameterSetName = 'BasicAuth')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSAvoidUsingConvertToSecureStringWithPlainText', '', Justification = 'api call provides in plain text')] + [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'No state is actually changing')] param( [Parameter(Mandatory)] From 10ddb011761265c3cfa89b749aabbd7ef0f5164b Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 18 Jan 2022 12:51:07 -0500 Subject: [PATCH 291/348] release prep --- RELEASE.md | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE.md b/RELEASE.md index e69de29..6829749 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -0,0 +1 @@ +- Add email type to custom variables, [#173](https://github.com/Snow-Shell/servicenow-powershell/issues/173) From b3fc819673a478ecfb53f5bc6d46f8ba1dc490cf Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 18 Jan 2022 17:51:50 +0000 Subject: [PATCH 292/348] Update manifest to 3.1.4 --- CHANGELOG.md | 5 ++ ServiceNow/ServiceNow.psd1 | 101 +++++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2161e4..5642854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.1.4 +- Add email type to custom variables, [#173](https://github.com/Snow-Shell/servicenow-powershell/issues/173) + + ## 3.1.3 - Fix [#167](https://github.com/Snow-Shell/servicenow-powershell/issues/167), fix ServiceNowTable not being populated on Linux due to file name case @@ -106,3 +110,4 @@ Be able to reference types from this config per table, removing the need to have - Add Get-ServiceNowAttachment - Add Get-ServiceNowAttachmentDetail - Add Remove-ServiceNowAttachment + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index dd8d627..a152ed5 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -1,17 +1,27 @@ - +# +# Module manifest for module 'ServiceNow' +# +# Generated by: Sam Martin Rick Arroues Greg Brownstein +# +# Generated on: 01/18/2022 +# + @{ # Script module or binary module file associated with this manifest. RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.3' +ModuleVersion = '3.1.4' + +# Supported PSEditions +# CompatiblePSEditions = @() # ID used to uniquely identify this module GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' # Author of this module -Author = 'Sam Martin', 'Rick Arroues', 'Greg Brownstein' +Author = 'Sam Martin Rick Arroues Greg Brownstein' # Company or vendor of this module CompanyName = 'None' @@ -22,23 +32,23 @@ Copyright = '(c) 2015-2021 Snow-Shell. All rights reserved.' # Description of the functionality provided by this module Description = 'Automate against ServiceNow service and asset management. This module can be used standalone or with Azure Automation.' -# Minimum version of the Windows PowerShell engine required by this module -# PowerShellVersion = '3.0' +# Minimum version of the PowerShell engine required by this module +# PowerShellVersion = '' -# Name of the Windows PowerShell host required by this module +# Name of the PowerShell host required by this module # PowerShellHostName = '' -# Minimum version of the Windows PowerShell host required by this module +# Minimum version of the PowerShell host required by this module # PowerShellHostVersion = '' -# Minimum version of Microsoft .NET Framework required by this module +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. # DotNetFrameworkVersion = '' -# Minimum version of the common language runtime (CLR) required by this module -# CLRVersion = '' +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# ClrVersion = '' # Processor architecture (None, X86, Amd64) required by this module -# ProcessorArchitecture = 'None' +# ProcessorArchitecture = '' # Modules that must be imported into the global environment prior to importing this module # RequiredModules = @() @@ -53,20 +63,42 @@ Description = 'Automate against ServiceNow service and asset management. This m # TypesToProcess = @() # Format files (.ps1xml) to be loaded when importing this module -FormatsToProcess = @('ServiceNow.format.ps1xml') +FormatsToProcess = 'ServiceNow.format.ps1xml' # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess NestedModules = @() -# Functions to export from this module - FunctionsToExport = @('Get-ServiceNowRecordInterim','New-ServiceNowConfigurationItem','Get-ServiceNowRecord','New-ServiceNowSession','Add-ServiceNowAttachment','Get-ServiceNowAttachment','Export-ServiceNowAttachment','Get-ServiceNowChangeRequest','Get-ServiceNowConfigurationItem','Get-ServiceNowIncident','Get-ServiceNowRequest','Get-ServiceNowRequestedItem','Get-ServiceNowTable','Get-ServiceNowTableEntry','Get-ServiceNowUser','Get-ServiceNowUserGroup','New-ServiceNowChangeRequest','New-ServiceNowIncident','New-ServiceNowQuery','New-ServiceNowRecord','Remove-ServiceNowAttachment','Remove-ServiceNowRecord','Update-ServiceNowChangeRequest','Update-ServiceNowIncident','Update-ServiceNowRequestedItem','Update-ServiceNowRecord') - - # Variables to export from this module - VariablesToExport = @('ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable') - - AliasesToExport = @('gsnr','Get-ServiceNowIncident','Get-ServiceNowChangeRequest', 'Get-ServiceNowConfigurationItem', 'Get-ServiceNowRequest', 'Get-ServiceNowRequestedItem', 'Get-ServiceNowUser', 'Get-ServiceNowUserGroup','Update-ServiceNowNumber') - - # List of all modules packaged with this module +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = 'Get-ServiceNowRecordInterim', 'New-ServiceNowConfigurationItem', + 'Get-ServiceNowRecord', 'New-ServiceNowSession', + 'Add-ServiceNowAttachment', 'Get-ServiceNowAttachment', + 'Export-ServiceNowAttachment', 'Get-ServiceNowChangeRequest', + 'Get-ServiceNowConfigurationItem', 'Get-ServiceNowIncident', + 'Get-ServiceNowRequest', 'Get-ServiceNowRequestedItem', + 'Get-ServiceNowTable', 'Get-ServiceNowTableEntry', + 'Get-ServiceNowUser', 'Get-ServiceNowUserGroup', + 'New-ServiceNowChangeRequest', 'New-ServiceNowIncident', + 'New-ServiceNowQuery', 'New-ServiceNowRecord', + 'Remove-ServiceNowAttachment', 'Remove-ServiceNowRecord', + 'Update-ServiceNowChangeRequest', 'Update-ServiceNowIncident', + 'Update-ServiceNowRequestedItem', 'Update-ServiceNowRecord' + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +CmdletsToExport = @() + +# Variables to export from this module +VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable' + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +AliasesToExport = 'gsnr', 'Get-ServiceNowIncident', 'Get-ServiceNowChangeRequest', + 'Get-ServiceNowConfigurationItem', 'Get-ServiceNowRequest', + 'Get-ServiceNowRequestedItem', 'Get-ServiceNowUser', + 'Get-ServiceNowUserGroup', 'Update-ServiceNowNumber' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module # ModuleList = @() # List of all files packaged with this module @@ -78,23 +110,38 @@ PrivateData = @{ PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. - Tags = @('Azure','Automation','ServiceNow','PSModule') + Tags = 'Azure','Automation','ServiceNow','PSModule' # A URL to the license for this module. - LicenseUri = 'https://github.com/Snow-Shell/servicenow-powershell/blob/master/LICENSE' + LicenseUri = 'https://github.com/Snow-Shell/servicenow-powershell/blob/master/LICENSE' # A URL to the main website for this project. - ProjectUri = 'https://github.com/Snow-Shell/servicenow-powershell' + ProjectUri = 'https://github.com/Snow-Shell/servicenow-powershell' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + ReleaseNotes = 'https://github.com/Snow-Shell/servicenow-powershell/blob/master/CHANGELOG.md' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() - ReleaseNotes = 'https://github.com/Snow-Shell/servicenow-powershell/blob/master/CHANGELOG.md' } # End of PSData hashtable -} # End of PrivateData hashtable + } # End of PrivateData hashtable # HelpInfo URI of this module -# HelpInfoURI = 'https://github.com/Snow-Shell/servicenow-powershell' +# HelpInfoURI = '' # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' } + From 0edcf5a015f940474c6f805b9371d770f5747ad6 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 9 Feb 2022 11:22:24 -0500 Subject: [PATCH 293/348] table name conversion for Get-ServiceNowAttachment (#177) --- RELEASE.md | 3 +- .../Public/Get-ServiceNowAttachment.ps1 | 41 ++++++++++--------- ServiceNow/config/main.json | 9 +++- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 6829749..bce8560 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1 +1,2 @@ -- Add email type to custom variables, [#173](https://github.com/Snow-Shell/servicenow-powershell/issues/173) +- Add table name translation to `Get-ServiceNowAttachment` where sys_class_name does not match table name +- Change .endswith operator from % to ENDSWITH as % was not working \ No newline at end of file diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 1783b17..f84092a 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -1,24 +1,24 @@ Function Get-ServiceNowAttachment { <# - + .SYNOPSIS Retrieve attachment details - + .DESCRIPTION Retrieve attachment details via table record or by advanced filtering. - + .PARAMETER Table Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. You can also provide any table name ad hoc. - + .PARAMETER Id Either the record sys_id or number. If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. - + .PARAMETER FileName Filter for a specific file name or part of a file name. - + .PARAMETER Filter Array or multidimensional array of fields and values to filter on. Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group'. @@ -39,19 +39,19 @@ Function Get-ServiceNowAttachment { .EXAMPLE Get-ServiceNowAttachment -Id 'INC1234567' - + Get attachment details for a specific record - + .EXAMPLE Get-ServiceNowAttachment -Id 'INC1234567' -FileName image.jpg - + Get attachment details for a specific record where file names match all or part of image.jpg - + .EXAMPLE Get-ServiceNowAttachment -Filter @('size_bytes', '-gt', '1000000') - + Get attachment details where size is greater than 1M. - + .INPUTS Table, Id @@ -112,17 +112,20 @@ Function Get-ServiceNowAttachment { $getParams.Table = $Table } $tableRecord = Get-ServiceNowRecord @getParams - + if ( -not $tableRecord ) { Write-Error "Record not found for Id '$Id'" continue } - - $params.Filter = @( - @('table_name', '-eq', $tableRecord.sys_class_name), - 'and', - @('table_sys_id', '-eq', $tableRecord.sys_id) - ) + + # perform lookup for known table names which might be different than sys_class_name + $tableName = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $tableRecord.sys_class_name.ToLower() -or $_.ClassName.ToLower() -eq $tableRecord.sys_class_name.ToLower() } | Select-Object -ExpandProperty Name + if ( $tableName ) { + $params.Filter = @(@('table_name', '-eq', $tableName), 'and', @('table_sys_id', '-eq', $tableRecord.sys_id)) + } + else { + $params.Filter = @(@('table_name', '-eq', $tableRecord.sys_class_name), 'and', @('table_sys_id', '-eq', $tableRecord.sys_id)) + } } if ( $FileName ) { diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 8ac8cc4..dae260f 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -61,6 +61,13 @@ "Type": "ServiceNow.ChangeTask", "NumberPrefix": "ctask", "DescriptionField": "short_description" + }, + { + "Name": "cmdb_ci_certificate", + "ClassName": "Unique Certificate", + "Type": "ServiceNow.UniqueCertificate", + "NumberPrefix": "", + "DescriptionField": "name" } ], "FilterOperators": [ @@ -162,7 +169,7 @@ }, { "Name": ".endswith", - "QueryOperator": "%", + "QueryOperator": "ENDSWITH", "Description": "field ends with the value", "NumValues": 1 }, From b5927602f7688989bedf903d231e9060a433b023 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 9 Feb 2022 16:23:08 +0000 Subject: [PATCH 294/348] Update manifest to 3.1.5 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5642854..ff3a1e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.1.5 +- Add table name translation to `Get-ServiceNowAttachment` where sys_class_name does not match table name +- Change .endswith operator from % to ENDSWITH as % was not working + ## 3.1.4 - Add email type to custom variables, [#173](https://github.com/Snow-Shell/servicenow-powershell/issues/173) @@ -111,3 +115,4 @@ Be able to reference types from this config per table, removing the need to have - Add Get-ServiceNowAttachmentDetail - Add Remove-ServiceNowAttachment + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index a152ed5..d1c2348 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 01/18/2022 +# Generated on: 02/09/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.4' +ModuleVersion = '3.1.5' # Supported PSEditions # CompatiblePSEditions = @() From cfd37b4d25da518bcaf574da7be8d8ef1ed7774a Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 9 Feb 2022 17:38:12 -0500 Subject: [PATCH 295/348] Add `AsValue` parameter to `Export-ServiceNowAttachment` (#178) --- RELEASE.md | 3 +- .../Public/Export-ServiceNowAttachment.ps1 | 45 ++++++++++++------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index bce8560..9a541fb 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,2 +1 @@ -- Add table name translation to `Get-ServiceNowAttachment` where sys_class_name does not match table name -- Change .endswith operator from % to ENDSWITH as % was not working \ No newline at end of file +- Add `AsValue` parameter to `Export-ServiceNowAttachment` to return attachment contents instead of writing to a file \ No newline at end of file diff --git a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 index 6bfed53..8eb4656 100644 --- a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 @@ -20,6 +20,9 @@ Allows the function to overwrite the existing file. .PARAMETER AppendNameWithSysID Adds the SysID to the file name. Intended for use when a ticket has multiple files with the same name. +.PARAMETER AsValue +Instead of writing to a file, return the attachment contents + .EXAMPLE Export-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' @@ -39,36 +42,44 @@ Save all attachments from the ticket. Filenames will be assigned from the attac Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -Destination $path -AllowOverwrite Save all attachments from the ticket to the destination allowing for overwriting the destination file. + +.EXAMPLE +Export-ServiceNowAttachment -SysId $SysId -AsValue +Return the contents of the attachment instead of writing to a file + #> Function Export-ServiceNowAttachment { - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'ToFile')] Param( - + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('sys_id')] [string] $SysId, - [Parameter(ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'ToFile', ValueFromPipelineByPropertyName)] [Alias('file_name')] [string] $FileName, # Out path to download files - [parameter()] + [parameter(ParameterSetName = 'ToFile')] [ValidateScript( { Test-Path $_ })] [string] $Destination = $PWD.Path, # Options impacting downloads - [parameter()] + [parameter(ParameterSetName = 'ToFile')] [switch] $AllowOverwrite, # Options impacting downloads - [parameter()] + [parameter(ParameterSetName = 'ToFile')] [switch] $AppendNameWithSysId, + [Parameter(ParameterSetName = 'ToPipeline', Mandatory)] + [switch] $AsValue, + [Parameter()] [Hashtable] $Connection, @@ -86,20 +97,22 @@ Function Export-ServiceNowAttachment { $params.Uri += '/attachment/' + $SysId + '/file' - $thisFileName = $FileName - If ( $AppendNameWithSysId.IsPresent ) { - $thisFileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($thisFileName), $SysId, [io.path]::GetExtension($thisFileName) - } - $outFile = Join-Path $Destination $thisFileName + if ( $PSCmdlet.ParameterSetName -eq 'ToFile' ) { + $thisFileName = $FileName + If ( $AppendNameWithSysId.IsPresent ) { + $thisFileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($thisFileName), $SysId, [io.path]::GetExtension($thisFileName) + } + $outFile = Join-Path $Destination $thisFileName - If ((Test-Path $outFile) -and -not $AllowOverwrite.IsPresent) { - throw ('The file ''{0}'' already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file.' -f $OutFile) - } + If ((Test-Path $outFile) -and -not $AllowOverwrite.IsPresent) { + throw ('The file ''{0}'' already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file.' -f $OutFile) + } - $params.OutFile = $outFile + $params.OutFile = $outFile + } If ($PSCmdlet.ShouldProcess($outFile, "Save attachment")) { - Invoke-WebRequest @params + Invoke-RestMethod @params } } end {} From 28cded07b733c7035db48321fb3c5a3e94d0da07 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 9 Feb 2022 22:39:24 +0000 Subject: [PATCH 296/348] Update manifest to 3.1.6 --- CHANGELOG.md | 4 ++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff3a1e4..472f9f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 3.1.6 +- Add `AsValue` parameter to `Export-ServiceNowAttachment` to return attachment contents instead of writing to a file + ## 3.1.5 - Add table name translation to `Get-ServiceNowAttachment` where sys_class_name does not match table name - Change .endswith operator from % to ENDSWITH as % was not working @@ -116,3 +119,4 @@ Be able to reference types from this config per table, removing the need to have - Add Remove-ServiceNowAttachment + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index d1c2348..dfb7003 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.5' +ModuleVersion = '3.1.6' # Supported PSEditions # CompatiblePSEditions = @() From 28e8db0ba570a63bd83b82372d43405e752b5f3e Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 10 Feb 2022 10:14:28 -0500 Subject: [PATCH 297/348] asvalue for gsnr (#179) --- RELEASE.md | 3 +- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 24 ++++++++- ServiceNow/ServiceNow.format.ps1xml | 57 ++++++++++++++++++++++ 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 9a541fb..dad75f2 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1 +1,2 @@ -- Add `AsValue` parameter to `Export-ServiceNowAttachment` to return attachment contents instead of writing to a file \ No newline at end of file +- Add `AsValue` parameter to `Get-ServiceNowRecord` to return the underlying value for a property instead of a pscustomobject. Get your sys_id directly! +- Add formatting for Unique Certificate (cmdb_ci_certificate) table \ No newline at end of file diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index d16063e..24d4140 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -49,6 +49,11 @@ For instance, an RITM may have custom variables, but the associated tasks may not. A property named 'CustomVariable' will be added to the return object. +.PARAMETER AsValue + Return the underlying value instead of pscustomobject. + Only valid when the Property parameter is set to 1 item. + Helpful when retrieving sys_id for example. + .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance @@ -105,6 +110,10 @@ Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -First 5 Get the first 5 change requests and retrieve custom variable info +.EXAMPLE + Get-ServiceNowRecord -Table 'cmdb_ci' -Property sys_id -First 1 -AsValue + Get the underlying value for a property instead of a pscustomobject where the value needs to be extracted + .EXAMPLE gsnr RITM0010001 Get a specific record by number using the function alias @@ -175,6 +184,9 @@ function Get-ServiceNowRecord { [Parameter()] [switch] $IncludeCustomVariable, + [Parameter()] + [switch] $AsValue, + [Parameter()] [hashtable] $Connection, @@ -336,12 +348,20 @@ function Get-ServiceNowRecord { else { # format the results - if ( -not $Property ) { + if ( $Property ) { + if ( $Property.Count -eq 1 -and $AsValue ) { + $result | Select-Object -ExpandProperty $result.PSObject.Properties.Name + } + else { + $result + } + } + else { if ($thisTable.Type) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $thisTable.Type) } } + $result } - $result } } } diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index bb6a216..51a6050 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -472,5 +472,62 @@ + + ServiceNow.UniqueCertificate + + ServiceNow.UniqueCertificate + + + + + + 30 + + + + 20 + + + + 15 + + + + 30 + + + + 32 + + + + + + + name + + + valid_to + + + state + + + + if ($_.issuer.display_value) { + $_.issuer.display_value + } else { + $_.issuer.value + } + + + + sys_id + + + + + + From 79784313ac33f5fd927d9ffbcaa9cce9abaf7f77 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 10 Feb 2022 15:15:06 +0000 Subject: [PATCH 298/348] Update manifest to 3.1.7 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 472f9f1..8eade30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.1.7 +- Add `AsValue` parameter to `Get-ServiceNowRecord` to return the underlying value for a property instead of a pscustomobject. Get your sys_id directly! +- Add formatting for Unique Certificate (cmdb_ci_certificate) table + ## 3.1.6 - Add `AsValue` parameter to `Export-ServiceNowAttachment` to return attachment contents instead of writing to a file @@ -120,3 +124,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index dfb7003..2069dc5 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 02/09/2022 +# Generated on: 02/10/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.6' +ModuleVersion = '3.1.7' # Supported PSEditions # CompatiblePSEditions = @() From 84953e8f3d2568f5ef5dc9a4cf1af0bc4b3eae87 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 24 Mar 2022 21:27:51 -0400 Subject: [PATCH 299/348] Fix 172 - custom variable values not showing (#182) --- RELEASE.md | 6 +- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 238 +++++++++++---------- ServiceNow/ServiceNow.psd1 | 2 +- 3 files changed, 130 insertions(+), 116 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index dad75f2..246959e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,2 +1,4 @@ -- Add `AsValue` parameter to `Get-ServiceNowRecord` to return the underlying value for a property instead of a pscustomobject. Get your sys_id directly! -- Add formatting for Unique Certificate (cmdb_ci_certificate) table \ No newline at end of file +- Fix #172, `Get-ServiceNowRecord -IncludeCustomVariable` not returning values +- `Get-ServiceNowRecord -IncludeCustomVariable` 'variable.' prefix has been removed from custom variable property name. +- Add pipeline functionality to `-Id` parameter of `Get-ServiceNowRecord` +- Fix `Get-ServiceNowRecord -AsValue` causing error with some values \ No newline at end of file diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 24d4140..c5418a0 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -138,8 +138,8 @@ function Get-ServiceNowRecord { [Alias('sys_class_name')] [string] $Table, - [Parameter(ParameterSetName = 'Id', Mandatory, Position = 0)] - [Parameter(ParameterSetName = 'Table')] + [Parameter(ParameterSetName = 'Id', Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)] + [Parameter(ParameterSetName = 'Table', ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true @@ -194,146 +194,154 @@ function Get-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - $invokeParams = @{ - Filter = $Filter - Property = $Property - Sort = $Sort - DisplayValue = $DisplayValue - First = $PSCmdlet.PagingParameters.First - Skip = $PSCmdlet.PagingParameters.Skip - IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } + begin { + + $invokeParams = @{ + Property = $Property + Sort = $Sort + DisplayValue = $DisplayValue + First = $PSCmdlet.PagingParameters.First + Skip = $PSCmdlet.PagingParameters.Skip + IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } - if ( $Table ) { - $thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } - if ( -not $thisTable ) { - # we aren't aware of this table, create default config - $thisTable = @{ - Name = $Table - ClassName = $null - Type = $null - NumberPrefix = $null - DescriptionField = $null + if ( $Table ) { + $thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } + if ( -not $thisTable ) { + # we aren't aware of this table, create default config + $thisTable = @{ + Name = $Table + ClassName = $null + Type = $null + NumberPrefix = $null + DescriptionField = $null + } } } } - if ( $Id ) { - if ( $Id -match '^[a-zA-Z0-9]{32}$' ) { - if ( -not $thisTable ) { - throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' - } + process { - $idFilter = @('sys_id', '-eq', $Id) - } - else { - if ( -not $thisTable ) { - # get table name from prefix if only Id was provided - $idPrefix = ($Id | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() - Write-Debug "Id prefix is $idPrefix" - $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } + if ( $Id ) { + if ( $Id -match '^[a-zA-Z0-9]{32}$' ) { if ( -not $thisTable ) { - throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' } + + $idFilter = @('sys_id', '-eq', $Id) + } + else { + if ( -not $thisTable ) { + # get table name from prefix if only Id was provided + $idPrefix = ($Id | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() + Write-Debug "Id prefix is $idPrefix" + $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } + if ( -not $thisTable ) { + throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + } + } + $idFilter = @('number', '-eq', $Id) + } + + if ( $Filter ) { + $invokeParams.Filter = $Filter, 'and', $idFilter + } + else { + $invokeParams.Filter = $idFilter } - $idFilter = @('number', '-eq', $Id) - } - if ( $invokeParams.Filter ) { - $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter - } - else { - $invokeParams.Filter = $idFilter } - } + # we have the table, update the params + $invokeParams.Table = $thisTable.Name - # we have the table, update the params - $invokeParams.Table = $thisTable.Name + if ( $ParentId ) { + if ( $ParentId -match '^[a-zA-Z0-9]{32}$' ) { + $parentIdFilter = @('parent.sys_id', '-eq', $ParentId) + } + else { + $parentIdFilter = @('parent.number', '-eq', $ParentId) + } - if ( $ParentId ) { - if ( $ParentId -match '^[a-zA-Z0-9]{32}$' ) { - $parentIdFilter = @('parent.sys_id', '-eq', $ParentId) - } - else { - $parentIdFilter = @('parent.number', '-eq', $ParentId) + if ( $invokeParams.Filter ) { + $invokeParams.Filter = $invokeParams.Filter, 'and', $parentIdFilter + } + else { + $invokeParams.Filter = $parentIdFilter + } } - if ( $invokeParams.Filter ) { - $invokeParams.Filter = $invokeParams.Filter, 'and', $parentIdFilter - } - else { - $invokeParams.Filter = $parentIdFilter - } - } + if ( $Description ) { + # determine the field we should compare for 'description' and add the filter + if ( -not $thisTable.DescriptionField ) { + Write-Warning ('We do not have table ''{0}'' in the config; short_description will be used as the description field' -f $thisTable.Name) + $thisTable.DescriptionField = 'short_description' + } - if ( $Description ) { - # determine the field we should compare for 'description' and add the filter - if ( -not $thisTable.DescriptionField ) { - Write-Warning ('We do not have table ''{0}'' in the config; short_description will be used as the description field' -f $thisTable.Name) - $thisTable.DescriptionField = 'short_description' + if ( $invokeParams.Filter ) { + $invokeParams.Filter = $invokeParams.Filter, 'and', @($thisTable.DescriptionField, '-like', $Description) + } + else { + $invokeParams.Filter = @($thisTable.DescriptionField, '-like', $Description) + } } - if ( $invokeParams.Filter ) { - $invokeParams.Filter = $invokeParams.Filter, 'and', @($thisTable.DescriptionField, '-like', $Description) - } - else { - $invokeParams.Filter = @($thisTable.DescriptionField, '-like', $Description) + $addedSysIdProp = $false + # we need the sys_id value in order to get custom var data + # add it in if specific properties were requested and not part of the list + if ( $IncludeCustomVariable.IsPresent ) { + if ( $Property -and 'sys_id' -notin $Property ) { + $invokeParams.Property += 'sys_id' + $addedSysIdProp = $true + } } - } - $addedSysIdProp = $false - # we need the sys_id value in order to get custom var data - # add it in if specific properties were requested and not part of the list - if ( $IncludeCustomVariable.IsPresent ) { - if ( $Property -and 'sys_id' -notin $Property ) { - $invokeParams.Property += 'sys_id' - $addedSysIdProp = $true + # should use Get-ServiceNowAttachment, but put this here for ease of access + if ( $thisTable.Name -eq 'attachment' ) { + Write-Warning 'For attachments, use Get-ServiceNowAttachment' + $invokeParams.Remove('Table') | Out-Null + $invokeParams.UriLeaf = '/attachment' } - } - # should use Get-ServiceNowAttachment, but put this here for ease of access - if ( $thisTable.Name -eq 'attachment' ) { - Write-Warning 'For attachments, use Get-ServiceNowAttachment' - $invokeParams.Remove('Table') | Out-Null - $invokeParams.UriLeaf = '/attachment' - } + $result = Invoke-ServiceNowRestMethod @invokeParams - $result = Invoke-ServiceNowRestMethod @invokeParams + if ( $IncludeCustomVariable ) { + + # suppress warning when getting total count + $existingWarning = $WarningPreference + $WarningPreference = 'SilentlyContinue' - if ( $result ) { - if ( $IncludeCustomVariable.IsPresent ) { # for each record, get the variable names and then get the variable values foreach ($record in $result) { + $customVarParams = @{ - Table = 'sc_item_option_mtom' - Property = 'sc_item_option.item_option_new.name', 'sc_item_option.item_option_new.sys_name', 'sc_item_option.item_option_new.type' - Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22,26') - First = 1000 # hopefully there isn't more custom vars than this, but we need to overwrite the default of 10 + Table = 'sc_item_option_mtom' + Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22,26') + Property = 'sc_item_option.item_option_new.name', 'sc_item_option.value', 'sc_item_option.item_option_new.type', 'sc_item_option.item_option_new.question_text' + IncludeTotalCount = $true } - $customVars = Get-ServiceNowRecord @customVarParams - if ( $customVars ) { - $customValueParams = @{ - Table = $thisTable.Name - Filter = @('sys_id', '-eq', $record.sys_id) - Property = $customVars.'sc_item_option.item_option_new.name' | ForEach-Object { "variables.$_" } - } - $customValues = Get-ServiceNowRecord @customValueParams - - # custom vars will be a separate property on the return object - $customVarsOut = $customVars | ForEach-Object { - $varName = $_.'sc_item_option.item_option_new.name' - [pscustomobject] @{ - Name = 'variables.{0}' -f $varName - DisplayName = $_.'sc_item_option.item_option_new.sys_name' - Value = $customValues."variables.$varName" - } - } - $record | Add-Member @{ - 'CustomVariable' = $customVarsOut + $customVarsOut = Get-ServiceNowRecord @customVarParams + + $record | Add-Member @{ + 'CustomVariable' = $customVarsOut | Select-Object -Property ` + @{ + 'n' = 'Name' + 'e' = { $_.'sc_item_option.item_option_new.name' } + }, + @{ + 'n' = 'Value' + 'e' = { $_.'sc_item_option.value' } + }, + @{ + 'n' = 'DisplayName' + 'e' = { $_.'sc_item_option.item_option_new.question_text' } + }, + @{ + 'n' = 'Type' + 'e' = { $_.'sc_item_option.item_option_new.type' } } } @@ -344,13 +352,17 @@ function Get-ServiceNowRecord { $record } } + + $WarningPreference = $existingWarning + } else { # format the results if ( $Property ) { if ( $Property.Count -eq 1 -and $AsValue ) { - $result | Select-Object -ExpandProperty $result.PSObject.Properties.Name + $propName = $result | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' } | Select-Object -exp Name + $result | Select-Object -ExpandProperty $propName } else { $result diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 2069dc5..89ea6dd 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.7' +ModuleVersion = '3.1.8' # Supported PSEditions # CompatiblePSEditions = @() From 9811f68a349e3e03dc1823a0c9e84648857020a1 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 25 Mar 2022 02:02:23 +0000 Subject: [PATCH 300/348] Update manifest to 3.1.9 --- CHANGELOG.md | 7 +++++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8eade30..4dff1bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 3.1.9 +- Fix #172, `Get-ServiceNowRecord -IncludeCustomVariable` not returning values +- `Get-ServiceNowRecord -IncludeCustomVariable` 'variable.' prefix has been removed from custom variable property name. +- Add pipeline functionality to `-Id` parameter of `Get-ServiceNowRecord` +- Fix `Get-ServiceNowRecord -AsValue` causing error with some values + ## 3.1.7 - Add `AsValue` parameter to `Get-ServiceNowRecord` to return the underlying value for a property instead of a pscustomobject. Get your sys_id directly! - Add formatting for Unique Certificate (cmdb_ci_certificate) table @@ -125,3 +131,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 89ea6dd..c0e4179 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 02/10/2022 +# Generated on: 03/25/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.8' +ModuleVersion = '3.1.9' # Supported PSEditions # CompatiblePSEditions = @() From c5a6fbd0148c75709fa0487ea026cc053cfa8656 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 11 Apr 2022 09:42:25 -0400 Subject: [PATCH 301/348] fix 183 (#184) --- RELEASE.md | 7 ++--- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 18 ++++++----- ServiceNow/ServiceNow.format.ps1xml | 36 ++++++++++++++++++---- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 246959e..ae7b210 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,4 +1,3 @@ -- Fix #172, `Get-ServiceNowRecord -IncludeCustomVariable` not returning values -- `Get-ServiceNowRecord -IncludeCustomVariable` 'variable.' prefix has been removed from custom variable property name. -- Add pipeline functionality to `-Id` parameter of `Get-ServiceNowRecord` -- Fix `Get-ServiceNowRecord -AsValue` causing error with some values \ No newline at end of file +- Fix [#183](https://github.com/Snow-Shell/servicenow-powershell/issues/183), `Get-ServiceNowRecord -Filter` parameter not applying in some circumstances +- Update display formats to correctly show values when `-DisplayValue` is false +- Update `Get-ServiceNowRecord` help \ No newline at end of file diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index c5418a0..a366263 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -16,7 +16,7 @@ .PARAMETER ParentId The sys_id or number of the parent record. - For example, to get catalog tasks for a requested item, provide the RITM number as ParentId. + For example, to get catalog tasks for a requested item, provide the RITM number as ParentId and catalog task as the Table. .PARAMETER Description Filter results based on the 'description' field. The field will be different for each table. @@ -25,7 +25,7 @@ The comparison performed is a 'like'. .PARAMETER Property - Return one or more specific fields + Return one or more specific fields otherwise all fields will be returned .PARAMETER Filter Array or multidimensional array of fields and values to filter on. @@ -119,13 +119,16 @@ Get a specific record by number using the function alias .INPUTS - None + Id .OUTPUTS - System.Management.Automation.PSCustomObject + PSCustomObject. If -AsValue is used, the type will be the selected field. .LINK https://docs.servicenow.com/bundle/quebec-platform-user-interface/page/use/common-ui-elements/reference/r_OpAvailableFiltersQueries.html + +.LINK + https://developer.servicenow.com/dev.do#!/reference/api/sandiego/rest/c_TableAPI#table-GET #> function Get-ServiceNowRecord { @@ -197,6 +200,7 @@ function Get-ServiceNowRecord { begin { $invokeParams = @{ + Filter = $Filter Property = $Property Sort = $Sort DisplayValue = $DisplayValue @@ -245,8 +249,8 @@ function Get-ServiceNowRecord { $idFilter = @('number', '-eq', $Id) } - if ( $Filter ) { - $invokeParams.Filter = $Filter, 'and', $idFilter + if ( $invokeParams.Filter ) { + $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter } else { $invokeParams.Filter = $idFilter @@ -291,7 +295,7 @@ function Get-ServiceNowRecord { $addedSysIdProp = $false # we need the sys_id value in order to get custom var data # add it in if specific properties were requested and not part of the list - if ( $IncludeCustomVariable.IsPresent ) { + if ( $IncludeCustomVariable ) { if ( $Property -and 'sys_id' -notin $Property ) { $invokeParams.Property += 'sys_id' $addedSysIdProp = $true diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index 51a6050..8990bc0 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -51,7 +51,11 @@ - $_.assigned_to.display_value + if ($_.assigned_to.display_value) { + $_.assigned_to.display_value + } else { + $_.assigned_to.value + } @@ -59,7 +63,11 @@ - $_.cmdb_ci.display_value + if ($_.cmdb_ci.display_value) { + $_.cmdb_ci.display_value + } else { + $_.cmdb_ci.value + } @@ -116,7 +124,11 @@ - $_.assigned_to.display_value + if ($_.assigned_to.display_value) { + $_.assigned_to.display_value + } else { + $_.assigned_to.value + } @@ -176,7 +188,11 @@ - $_.assigned_to.display_value + if ($_.assigned_to.display_value) { + $_.assigned_to.display_value + } else { + $_.assigned_to.value + } @@ -367,7 +383,11 @@ - $_.request_item.display_value + if ($_.request_item.display_value) { + $_.request_item.display_value + } else { + $_.request_item.value + } @@ -420,7 +440,11 @@ - $_.change_request.display_value + if ($_.change_request.display_value) { + $_.change_request.display_value + } else { + $_.change_request.value + } From aadc51579eb5dca1d8214c717bfe1ec576e29674 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 11 Apr 2022 13:43:06 +0000 Subject: [PATCH 302/348] Update manifest to 3.1.10 --- CHANGELOG.md | 6 ++++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dff1bf..56696a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.1.10 +- Fix [#183](https://github.com/Snow-Shell/servicenow-powershell/issues/183), `Get-ServiceNowRecord -Filter` parameter not applying in some circumstances +- Update display formats to correctly show values when `-DisplayValue` is false +- Update `Get-ServiceNowRecord` help + ## 3.1.9 - Fix #172, `Get-ServiceNowRecord -IncludeCustomVariable` not returning values - `Get-ServiceNowRecord -IncludeCustomVariable` 'variable.' prefix has been removed from custom variable property name. @@ -132,3 +137,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index c0e4179..0b733af 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 03/25/2022 +# Generated on: 04/11/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.9' +ModuleVersion = '3.1.10' # Supported PSEditions # CompatiblePSEditions = @() From ace9563faba0caa29a2ccaae944c5e94f0cdc5bc Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 6 May 2022 16:53:37 -0400 Subject: [PATCH 303/348] export record (#187) --- ServiceNow/Public/Export-ServiceNowRecord.ps1 | 170 ++++++++++++++++++ ServiceNow/ServiceNow.psd1 | 2 +- 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 ServiceNow/Public/Export-ServiceNowRecord.ps1 diff --git a/ServiceNow/Public/Export-ServiceNowRecord.ps1 b/ServiceNow/Public/Export-ServiceNowRecord.ps1 new file mode 100644 index 0000000..fd247b8 --- /dev/null +++ b/ServiceNow/Public/Export-ServiceNowRecord.ps1 @@ -0,0 +1,170 @@ +<# +.SYNOPSIS + Export table records to a file + +.DESCRIPTION + Export table records in csv, xml, xls, xlsx, or pdf format. + You can filter, sort, and choose specific properties to include in the report. + Only basic authentication is supported. + Export configurations, eg. row limit, can be found at System Properties->Import Export. + +.PARAMETER Table + Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. + You can also provide any table name ad hoc. + +.PARAMETER Id + Either the record sys_id or number. + If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. + +.PARAMETER Property + Return one or more specific fields otherwise all fields will be returned + +.PARAMETER Filter + Array or multidimensional array of fields and values to filter on. + Each array should be of the format @(field, comparison operator, value) separated by a join, either 'and', 'or', or 'group'. + For a complete list of comparison operators, see $script:ServiceNowOperator and use Name in your filter. + See the examples. + +.PARAMETER Sort + Array or multidimensional array of fields to sort on. + Each array should be of the format @(field, asc/desc). + +.PARAMETER Path + Path to output file including the file name. + File extension must be either .csv, .xml, .xls, .xlsx, or .pdf. + +.PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. + +.EXAMPLE + Export-ServiceNowRecord -Id RITM0010001 -Path .\out.pdf + Export a specific record by number + +.EXAMPLE + Export-ServiceNowRecord -Table incident -Filter @('assigned_to.name', '-like', 'greg') -Path .\out.xlsx + Export incident records where the assigned to user's name contains greg + +.EXAMPLE + $filter = @('state', '-eq', '1'), + '-and', + @('short_description','-like', 'powershell'), + '-group', + @('state', '-eq', '2') + PS > Export-ServiceNowRecord -Table incident -Filter $filter -Path .\out.pdf + Export incident records where state is New and short description contains the word powershell or state is In Progress. + The first 2 filters are combined and then or'd against the last. + +.EXAMPLE + Export-ServiceNowRecord -Table 'Incident' -Filter @('opened_at', '-between', (Get-Date).AddMonths(-24), (get-date).AddMonths(-12)) -Path .\out.pdf + Export incident records that were opened between 1 and 2 years ago + +.EXAMPLE + Export-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Sort @('opened_at', 'desc') -Path .\out.pdf + Export incident records where state equals New and sort by the field opened_at descending + +.LINK + https://docs.servicenow.com/bundle/rome-platform-user-interface/page/use/navigation/task/navigate-using-url.html + +.LINK + https://docs.servicenow.com/bundle/sandiego-platform-administration/page/administer/exporting-data/task/t_ExportDirectlyFromTheURL.html#t_ExportDirectlyFromTheURL +#> +function Export-ServiceNowRecord { + + [CmdletBinding(DefaultParameterSetName = 'Id')] + + Param ( + [Parameter(ParameterSetName = 'Table', Mandatory)] + [Alias('sys_class_name')] + [string] $Table, + + [Parameter(ParameterSetName = 'Id', Mandatory, Position = 0)] + [Parameter(ParameterSetName = 'Table')] + [ValidateScript( { + if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { + $true + } else { + throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' + } + })] + [Alias('sys_id', 'number')] + [string] $Id, + + [Parameter()] + [Alias('Fields', 'Properties')] + [string[]] $Property, + + [Parameter()] + [System.Collections.ArrayList] $Filter, + + [parameter()] + [ValidateNotNullOrEmpty()] + [System.Collections.ArrayList] $Sort, + + [Parameter(Mandatory)] + [ValidateScript({ + $allowedExts = '.csv', '.xml', '.pdf', '.xls', '.xlsx' + if ([System.IO.Path]::GetExtension($_).ToLower() -in $allowedExts ) { + $true + } else { + throw ('File extension must be one of {0}' -f ($allowedExts -join ', ')) + } + })] + [string] $Path, + + [Parameter()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) + + process { + + $newFilter = $Filter + + if ( $Table ) { + $thisTable = $Table + } + + if ( $Id ) { + if ( $Id -match '^[a-zA-Z0-9]{32}$' ) { + if ( -not $thisTable ) { + throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' + } + + $newFilter = @('sys_id', '-eq', $Id) + } else { + if ( -not $thisTable ) { + # get table name from prefix if only Id was provided + $idPrefix = ($Id | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() + Write-Debug "Id prefix is $idPrefix" + $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } | Select-Object -ExpandProperty Name + if ( -not $thisTable ) { + throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + } + } + $newFilter = @('number', '-eq', $Id) + } + } + + $params = Get-ServiceNowAuth -S $ServiceNowSession + $params.Body = @{ + 'sysparm_query' = (New-ServiceNowQuery -Filter $newFilter -Sort $Sort) + } + + if ($Property) { + $params.Body.sysparm_fields = ($Property -join ',').ToLower() + } + + $params.OutFile = $Path + + # need to tell SN the format, get it from file extension + $format = [System.IO.Path]::GetExtension($Path).Replace('.', '').ToUpper() + + # only exception to 'extension is the format' rule + if ( $format -eq 'XLS' ) { $format = 'EXCEL' } + + $params.Uri = 'https://{0}/{1}_list.do?{2}' -f $ServiceNowSession.Domain, $thisTable, $format + + Write-Verbose ($params | ConvertTo-Json) + Invoke-RestMethod @params + + } +} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 0b733af..842761d 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -81,7 +81,7 @@ FunctionsToExport = 'Get-ServiceNowRecordInterim', 'New-ServiceNowConfigurationI 'New-ServiceNowQuery', 'New-ServiceNowRecord', 'Remove-ServiceNowAttachment', 'Remove-ServiceNowRecord', 'Update-ServiceNowChangeRequest', 'Update-ServiceNowIncident', - 'Update-ServiceNowRequestedItem', 'Update-ServiceNowRecord' + 'Update-ServiceNowRequestedItem', 'Update-ServiceNowRecord', 'Export-ServiceNowRecord' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() From a5ee3008618ba5af065ca537a7274986c34fd00f Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 6 May 2022 18:43:06 -0400 Subject: [PATCH 304/348] Update RELEASE.md --- RELEASE.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index ae7b210..68b2a5c 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,3 +1 @@ -- Fix [#183](https://github.com/Snow-Shell/servicenow-powershell/issues/183), `Get-ServiceNowRecord -Filter` parameter not applying in some circumstances -- Update display formats to correctly show values when `-DisplayValue` is false -- Update `Get-ServiceNowRecord` help \ No newline at end of file +- Add `Export-ServiceNowRecord` to write records to csv, xls, xlsx, xml, or pdf. Supports filtering, sorting, and specific properties just like `Get-ServiceNowRecord`. [#186](https://github.com/Snow-Shell/servicenow-powershell/issues/186) From 814241285f94b678d4bee265fb31956c916ead43 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 6 May 2022 22:43:55 +0000 Subject: [PATCH 305/348] Update manifest to 3.1.11 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56696a8..e519873 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.1.11 +- Add `Export-ServiceNowRecord` to write records to csv, xls, xlsx, xml, or pdf. Supports filtering, sorting, and specific properties just like `Get-ServiceNowRecord`. [#186](https://github.com/Snow-Shell/servicenow-powershell/issues/186) + + ## 3.1.10 - Fix [#183](https://github.com/Snow-Shell/servicenow-powershell/issues/183), `Get-ServiceNowRecord -Filter` parameter not applying in some circumstances - Update display formats to correctly show values when `-DisplayValue` is false @@ -138,3 +142,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 842761d..04eeb57 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 04/11/2022 +# Generated on: 05/06/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.10' +ModuleVersion = '3.1.11' # Supported PSEditions # CompatiblePSEditions = @() @@ -81,7 +81,8 @@ FunctionsToExport = 'Get-ServiceNowRecordInterim', 'New-ServiceNowConfigurationI 'New-ServiceNowQuery', 'New-ServiceNowRecord', 'Remove-ServiceNowAttachment', 'Remove-ServiceNowRecord', 'Update-ServiceNowChangeRequest', 'Update-ServiceNowIncident', - 'Update-ServiceNowRequestedItem', 'Update-ServiceNowRecord', 'Export-ServiceNowRecord' + 'Update-ServiceNowRequestedItem', 'Update-ServiceNowRecord', + 'Export-ServiceNowRecord' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() From 30f259d6519e3d4b4a7a64771cb71b0d5427bdb1 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 17 May 2022 07:43:52 -0400 Subject: [PATCH 306/348] Fix 188 (#189) --- .../Public/Add-ServiceNowAttachment.ps1 | 142 ++++++++++++------ ServiceNow/Public/Export-ServiceNowRecord.ps1 | 14 +- .../Public/Get-ServiceNowAttachment.ps1 | 85 +++++++---- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 26 ++-- ServiceNow/Public/Update-ServiceNowRecord.ps1 | 14 +- ServiceNow/config/main.json | 7 + 6 files changed, 184 insertions(+), 104 deletions(-) diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 1b1b30f..805fa8e 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -1,39 +1,65 @@ Function Add-ServiceNowAttachment { <# .SYNOPSIS - Attaches a file to an existing ticket. + Attaches a file to an existing record. .DESCRIPTION - Attaches a file to an existing ticket. - - .PARAMETER Number - ServiceNow ticket number + Attaches a file to an existing record. .PARAMETER Table - ServiceNow ticket table name + Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. + You can also provide any table name ad hoc. + If using pipeline and this is failing, most likely the table name and class do not match. + In this case, provide this value directly. + + .PARAMETER Id + Either the record sys_id or number. + If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. .PARAMETER File - A valid path to the file to attach + Path to one or more files to attach + + .PARAMETER ContentType + Content (MIME) type for the file being uploaded. + This value will be automatically determined by default, but can be overridden with this parameter. + + .PARAMETER PassThru + Return the newly created attachment details + + .PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + + .PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. .EXAMPLE - Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt, .\File02.txt - - Upload one or more files to a ServiceNow ticket by specifing the number and table + Add-ServiceNowAttachment -Id INC0000010 -File @('.\File01.txt', '.\File02.txt') + + Upload one or more files by record number .EXAMPLE - New-ServiceNowIncident @params -PassThru | Add-ServiceNowAttachment -File File01.txt - + Add-ServiceNowAttachment -Table incident -Id 2306c37c1bafc9100774ebd1b24bcb6d -File @('.\File01.txt', '.\File02.txt') + + Upload one or more files by record sys_id + + .EXAMPLE + New-ServiceNowIncident @params -PassThru | Add-ServiceNowAttachment -File file01.txt + Create a new incident and add an attachment .EXAMPLE - Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt -ContentType 'text/plain' - - Upload a file and specify the MIME type (content type). Should only be required if the function cannot automatically determine the type. + Add-ServiceNowAttachment -Id INC0000010 -File file01.txt -ContentType 'text/plain' + + Upload a file and specify the MIME type (content type). + Only required if the function cannot automatically determine the type. .EXAMPLE - Add-ServiceNowAttachment -Number $Number -Table $Table -File .\File01.txt -PassThru + Add-ServiceNowAttachment -Id INC0000010 -File file01.txt -PassThru + + Upload a file and receive back the file details - Upload a file and receive back the file details. + .INPUTS + Table, ID .OUTPUTS System.Management.Automation.PSCustomObject if -PassThru provided @@ -41,15 +67,22 @@ Function Add-ServiceNowAttachment { [OutputType([PSCustomObject[]])] [CmdletBinding(SupportsShouldProcess)] + Param( - # Table containing the entry [Parameter(ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, - [Parameter(Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [ValidateScript( { + if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { + $true + } else { + throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' + } + })] [Alias('sys_id', 'SysId', 'number')] - [string] $Id, + [string] $ID, [Parameter(Mandatory)] [ValidateScript( { @@ -65,13 +98,10 @@ Function Add-ServiceNowAttachment { [Parameter()] [switch] $PassThru, - # Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter()] - # [ValidateNotNullOrEmpty()] [Hashtable] $Connection, [Parameter()] - # [ValidateNotNullOrEmpty()] [hashtable] $ServiceNowSession = $script:ServiceNowSession ) @@ -79,27 +109,48 @@ Function Add-ServiceNowAttachment { process { - $getParams = @{ - Id = $Id - Property = 'sys_class_name', 'sys_id', 'number' - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } if ( $Table ) { - $getParams.Table = $Table + $thisTableName = $ServiceNowTable.Where{ $_.ClassName -eq $Table } | Select-Object -ExpandProperty Name + if ( -not $thisTableName ) { + $thisTableName = $Table + } } - $tableRecord = Get-ServiceNowRecord @getParams - if ( -not $tableRecord ) { - Write-Error "Record not found for Id '$Id'" - continue - } + if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { + if ( -not $thisTableName ) { + Write-Error 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an -Id with a prefix, eg. INC1234567, and the table will be automatically determined.' + Continue + } - If (-not $Table) { - $tableName = $tableRecord.sys_class_name - } - else { - $tableName = $Table + $thisSysId = $ID + + } else { + if ( -not $thisTableName ) { + $thisTable = $ServiceNowTable.Where{ $_.NumberPrefix -and $ID.ToLower().StartsWith($_.NumberPrefix) } + if ( $thisTable ) { + $thisTableName = $thisTable.Name + } else { + Write-Error ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + Continue + } + } + + $getParams = @{ + Table = $thisTableName + Id = $ID + Property = 'sys_id' + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + + $tableRecord = Get-ServiceNowRecord @getParams + + if ( -not $tableRecord ) { + Write-Error "Record not found for Id '$ID'" + continue + } + + $thisSysId = $tableRecord.sys_id } $auth = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession @@ -118,7 +169,7 @@ Function Add-ServiceNowAttachment { # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot # $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl, $Table, $TableSysID, $FileData.Name $invokeRestMethodSplat = $auth - $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $tableName, $tableRecord.sys_id, $FileData.Name + $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $thisTableName, $thisSysId, $FileData.Name $invokeRestMethodSplat.Headers += @{'Content-Type' = $ContentType } $invokeRestMethodSplat.UseBasicParsing = $true $invokeRestMethodSplat += @{ @@ -126,23 +177,20 @@ Function Add-ServiceNowAttachment { InFile = $FileData.FullName } - If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $tableName, $tableRecord.number), ('Add attachment {0}' -f $FileData.FullName))) { + If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $thisTableName, $thisSysId), ('Add attachment {0}' -f $FileData.FullName))) { Write-Verbose ($invokeRestMethodSplat | ConvertTo-Json) $response = Invoke-WebRequest @invokeRestMethodSplat if ( $response.Content ) { - if ( $PassThru.IsPresent ) { + if ( $PassThru ) { $content = $response.content | ConvertFrom-Json $content.result } - } - else { + } else { # invoke-webrequest didn't throw an error, but we didn't get content back either throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) } } } } - - end {} } diff --git a/ServiceNow/Public/Export-ServiceNowRecord.ps1 b/ServiceNow/Public/Export-ServiceNowRecord.ps1 index fd247b8..8999fac 100644 --- a/ServiceNow/Public/Export-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Export-ServiceNowRecord.ps1 @@ -87,7 +87,7 @@ function Export-ServiceNowRecord { } })] [Alias('sys_id', 'number')] - [string] $Id, + [string] $ID, [Parameter()] [Alias('Fields', 'Properties')] @@ -123,24 +123,24 @@ function Export-ServiceNowRecord { $thisTable = $Table } - if ( $Id ) { - if ( $Id -match '^[a-zA-Z0-9]{32}$' ) { + if ( $ID ) { + if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { if ( -not $thisTable ) { throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' } - $newFilter = @('sys_id', '-eq', $Id) + $newFilter = @('sys_id', '-eq', $ID) } else { if ( -not $thisTable ) { # get table name from prefix if only Id was provided - $idPrefix = ($Id | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() + $idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() Write-Debug "Id prefix is $idPrefix" $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } | Select-Object -ExpandProperty Name if ( -not $thisTable ) { - throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) } } - $newFilter = @('number', '-eq', $Id) + $newFilter = @('number', '-eq', $ID) } } diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index f84092a..94033f0 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -11,6 +11,8 @@ Function Get-ServiceNowAttachment { .PARAMETER Table Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. You can also provide any table name ad hoc. + If using pipeline and not getting the expected response, most likely the table name and class do not match. + In this case, provide this value directly. .PARAMETER Id Either the record sys_id or number. @@ -53,24 +55,30 @@ Function Get-ServiceNowAttachment { Get attachment details where size is greater than 1M. .INPUTS - Table, Id + Table, ID .OUTPUTS System.Management.Automation.PSCustomObject #> [OutputType([System.Management.Automation.PSCustomObject[]])] - [CmdletBinding(DefaultParameterSetName = 'Filter', SupportsPaging)] + [CmdletBinding(SupportsPaging)] Param( - [Parameter(ParameterSetName = 'Table', Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, - [Parameter(ParameterSetName = 'Id', Mandatory, ValueFromPipelineByPropertyName)] - [Parameter(ParameterSetName = 'Table', Mandatory, ValueFromPipelineByPropertyName)] + [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] + [ValidateScript( { + if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { + $true + } else { + throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' + } + })] [Alias('sys_id', 'SysId', 'number')] - [string] $Id, + [string] $ID, [parameter()] [string] $FileName, @@ -89,9 +97,7 @@ Function Get-ServiceNowAttachment { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - begin {} - - process { + begin { $params = @{ UriLeaf = '/attachment' First = $PSCmdlet.PagingParameters.First @@ -101,38 +107,60 @@ Function Get-ServiceNowAttachment { ServiceNowSession = $ServiceNowSession } - if ( $PSCmdlet.ParameterSetName -in 'Table', 'Id' ) { + } + + process { + + if ( $Table ) { + $thisTableName = $ServiceNowTable.Where{ $_.ClassName -eq $Table } | Select-Object -ExpandProperty Name + if ( -not $thisTableName ) { + $thisTableName = $Table + } + } + + if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { + if ( -not $thisTableName ) { + Write-Error 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an -Id with a prefix, eg. INC1234567, and the table will be automatically determined.' + Continue + } + + $thisSysId = $ID + + } else { + if ( -not $thisTableName ) { + $thisTable = $ServiceNowTable.Where{ $_.NumberPrefix -and $ID.ToLower().StartsWith($_.NumberPrefix) } + if ( $thisTable ) { + $thisTableName = $thisTable.Name + } else { + Write-Error ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + Continue + } + } + $getParams = @{ - Id = $Id - Property = 'sys_class_name', 'sys_id' + Table = $thisTableName + Id = $ID + Property = 'sys_id' Connection = $Connection ServiceNowSession = $ServiceNowSession } - if ( $Table ) { - $getParams.Table = $Table - } + $tableRecord = Get-ServiceNowRecord @getParams if ( -not $tableRecord ) { - Write-Error "Record not found for Id '$Id'" + Write-Error "Record not found for ID '$ID'" continue } - # perform lookup for known table names which might be different than sys_class_name - $tableName = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $tableRecord.sys_class_name.ToLower() -or $_.ClassName.ToLower() -eq $tableRecord.sys_class_name.ToLower() } | Select-Object -ExpandProperty Name - if ( $tableName ) { - $params.Filter = @(@('table_name', '-eq', $tableName), 'and', @('table_sys_id', '-eq', $tableRecord.sys_id)) - } - else { - $params.Filter = @(@('table_name', '-eq', $tableRecord.sys_class_name), 'and', @('table_sys_id', '-eq', $tableRecord.sys_id)) - } + $thisSysId = $tableRecord.sys_id } + $params.Filter = @(@('table_name', '-eq', $thisTableName), 'and', @('table_sys_id', '-eq', $thisSysId)) + if ( $FileName ) { if ( $params.Filter ) { $params.Filter += 'and', @('file_name', '-like', $FileName) - } - else { + } else { $params.Filter = @('file_name', '-like', $FileName) } } @@ -140,8 +168,7 @@ Function Get-ServiceNowAttachment { if ( $Filter ) { if ( $params.Filter ) { $params.Filter += 'and', $Filter - } - else { + } else { $params.Filter = $Filter } } @@ -154,6 +181,4 @@ Function Get-ServiceNowAttachment { } } - - end {} } diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index a366263..5450908 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -119,7 +119,7 @@ Get a specific record by number using the function alias .INPUTS - Id + ID .OUTPUTS PSCustomObject. If -AsValue is used, the type will be the selected field. @@ -152,7 +152,7 @@ function Get-ServiceNowRecord { } })] [Alias('sys_id', 'number')] - [string] $Id, + [string] $ID, [Parameter()] [ValidateScript( { @@ -163,7 +163,7 @@ function Get-ServiceNowRecord { throw 'ParentId must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' } })] - [string] $ParentId, + [string] $ParentID, [Parameter()] [string] $Description, @@ -228,25 +228,25 @@ function Get-ServiceNowRecord { process { - if ( $Id ) { - if ( $Id -match '^[a-zA-Z0-9]{32}$' ) { + if ( $ID ) { + if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { if ( -not $thisTable ) { throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' } - $idFilter = @('sys_id', '-eq', $Id) + $idFilter = @('sys_id', '-eq', $ID) } else { if ( -not $thisTable ) { # get table name from prefix if only Id was provided - $idPrefix = ($Id | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() + $idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() Write-Debug "Id prefix is $idPrefix" $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } if ( -not $thisTable ) { - throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $Id, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) } } - $idFilter = @('number', '-eq', $Id) + $idFilter = @('number', '-eq', $ID) } if ( $invokeParams.Filter ) { @@ -261,12 +261,12 @@ function Get-ServiceNowRecord { # we have the table, update the params $invokeParams.Table = $thisTable.Name - if ( $ParentId ) { - if ( $ParentId -match '^[a-zA-Z0-9]{32}$' ) { - $parentIdFilter = @('parent.sys_id', '-eq', $ParentId) + if ( $ParentID ) { + if ( $ParentID -match '^[a-zA-Z0-9]{32}$' ) { + $parentIdFilter = @('parent.sys_id', '-eq', $ParentID) } else { - $parentIdFilter = @('parent.number', '-eq', $ParentId) + $parentIdFilter = @('parent.number', '-eq', $ParentID) } if ( $invokeParams.Filter ) { diff --git a/ServiceNow/Public/Update-ServiceNowRecord.ps1 b/ServiceNow/Public/Update-ServiceNowRecord.ps1 index d2ca623..49071f8 100644 --- a/ServiceNow/Public/Update-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRecord.ps1 @@ -18,13 +18,13 @@ .PARAMETER PassThru If provided, the updated record will be returned - + .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance .PARAMETER ServiceNowSession ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. - + .EXAMPLE Update-ServiceNowRecord -Table incident -Id 'INC0010001' -Values @{State = 'Closed'} Close an incident record @@ -47,7 +47,7 @@ function Update-ServiceNowRecord { [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id', 'SysId', 'number')] - [string] $Id, + [string] $ID, [parameter(Mandatory)] [hashtable] $Values, @@ -66,15 +66,15 @@ function Update-ServiceNowRecord { process { - if ( $Table -and ($Id -match '[a-zA-Z0-9]{32}') ) { + if ( $Table -and ($ID -match '[a-zA-Z0-9]{32}') ) { # we already have table name and sys_id, no more to do before update $tableName = $Table - $sysId = $Id + $sysId = $ID } else { # get needed details, table name and sys_id, for update $getParams = @{ - Id = $Id + Id = $ID Property = 'sys_class_name', 'sys_id', 'number' Connection = $Connection ServiceNowSession = $ServiceNowSession @@ -91,7 +91,7 @@ function Update-ServiceNowRecord { $sysId = $thisRecord.sys_id } else { - Write-Error ('Record not found for Id ''{0}''' -f $Id) + Write-Error ('Record not found for Id ''{0}''' -f $ID) continue } } diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index dae260f..9b27e94 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -68,6 +68,13 @@ "Type": "ServiceNow.UniqueCertificate", "NumberPrefix": "", "DescriptionField": "name" + }, + { + "Name": "kb_knowledge", + "ClassName": "Knowledge", + "Type": "ServiceNow.Knowledge", + "NumberPrefix": "kb", + "DescriptionField": "short_description" } ], "FilterOperators": [ From d4909298a8193b416a58a1c04cc9122370752278 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 17 May 2022 07:47:22 -0400 Subject: [PATCH 307/348] Update RELEASE.md --- RELEASE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 68b2a5c..6c5d6b5 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1 +1,2 @@ -- Add `Export-ServiceNowRecord` to write records to csv, xls, xlsx, xml, or pdf. Supports filtering, sorting, and specific properties just like `Get-ServiceNowRecord`. [#186](https://github.com/Snow-Shell/servicenow-powershell/issues/186) +- Fix `Get-ServiceNowAttachment` returning 0 records when the table name didn't match the table class name, [#188](https://github.com/Snow-Shell/servicenow-powershell/issues/188) +- Update `Add-ServiceNowAttachment` `-Table` and `-ID` parameters with the same 'smarts' as other functions with table name lookup From 41c1c851098410ac70adeae256a3f70200fa1963 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 17 May 2022 07:47:53 -0400 Subject: [PATCH 308/348] increase minor version --- ServiceNow/ServiceNow.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 04eeb57..7288955 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.1.11' +ModuleVersion = '3.2' # Supported PSEditions # CompatiblePSEditions = @() From ba666782f3d8c1eacd8bc11d89c42814d764362e Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 17 May 2022 11:48:39 +0000 Subject: [PATCH 309/348] Update manifest to 3.2.0 --- CHANGELOG.md | 6 ++++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e519873..2e8296d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.2.0 +- Fix `Get-ServiceNowAttachment` returning 0 records when the table name didn't match the table class name, [#188](https://github.com/Snow-Shell/servicenow-powershell/issues/188) +- Update `Add-ServiceNowAttachment` `-Table` and `-ID` parameters with the same 'smarts' as other functions with table name lookup + + ## 3.1.11 - Add `Export-ServiceNowRecord` to write records to csv, xls, xlsx, xml, or pdf. Supports filtering, sorting, and specific properties just like `Get-ServiceNowRecord`. [#186](https://github.com/Snow-Shell/servicenow-powershell/issues/186) @@ -143,3 +148,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 7288955..80ff52c 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 05/06/2022 +# Generated on: 05/17/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.2' +ModuleVersion = '3.2.0' # Supported PSEditions # CompatiblePSEditions = @() From eccc33aa7271625fedbe124022c3918b9e1a64dd Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 21 Jun 2022 14:37:09 -0400 Subject: [PATCH 310/348] docker enablement (#193) --- .github/workflows/cd.yml | 22 ++++++++++++++++++++++ Dockerfile | 11 +++++++++++ RELEASE.md | 7 +++++-- Readme.md | 8 ++++++++ ServiceNow/Private/Get-ServiceNowAuth.ps1 | 20 ++++++++++++++------ ServiceNow/ServiceNow.psd1 | 2 +- 6 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 Dockerfile diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 662d672..2cfd716 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -11,6 +11,7 @@ jobs: - uses: actions/checkout@v2 with: token: ${{ secrets.CD_TOKEN }} + - name: Update psd version shell: pwsh run: | @@ -26,6 +27,7 @@ jobs: "New version: $newVersion" # set version to be used in later steps "module_new_version=$newVersion" | Out-File -FilePath $env:GITHUB_ENV -Append + - name: Update changelog shell: pwsh run: | @@ -33,6 +35,7 @@ jobs: $releaseNotes = Get-Content -Path '${{ github.workspace }}/RELEASE.md' -Raw $changelog = Get-Content -Path '${{ github.workspace }}/CHANGELOG.md' -Raw Set-Content -Path '${{ github.workspace }}/CHANGELOG.md' -Value ($newVersionString + "`r`n" + $releaseNotes + "`r`n`r`n" + $changelog) + - name: Update repo run: | git config --global user.name 'Greg Brownstein' @@ -42,14 +45,33 @@ jobs: git status git commit -m "Update manifest to ${{ env.module_new_version }}" git push + - name: Create GitHub release if: github.ref == 'refs/heads/master' uses: softprops/action-gh-release@v1 with: tag_name: v${{ env.module_new_version }} body_path: ${{ github.workspace }}/RELEASE.md + - name: Publish if: github.ref == 'refs/heads/master' shell: pwsh run: | Publish-Module -Path "${{ github.workspace }}/${{ env.module_name }}" -NuGetApiKey ${{ secrets.NUGET_KEY }} -Verbose + + - name: Login to dockerhub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build image + run: > + docker build + --pull + -t ${{ secrets.DOCKER_USERNAME }}/servicenow-module:latest + -t ${{ secrets.DOCKER_USERNAME }}/servicenow-module:${{ env.module_new_version }} + . + + - name: Publish image and tags + run: docker push --all-tags ${{ secrets.DOCKER_USERNAME }}/servicenow-module diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..987fc37 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM mcr.microsoft.com/powershell:latest + +RUN pwsh -Command 'Set-PSRepository PSGallery -InstallationPolicy Trusted; Install-Module ServiceNow -ErrorAction Stop' + +ENV SNOW_SERVER=${SNOW_SERVER} +ENV SNOW_TOKEN=${SNOW_TOKEN} +ENV SNOW_USER=${SNOW_USER} +ENV SNOW_PASS=${SNOW_PASS} +ENV POWERSHELL_TELEMETRY_OPTOUT=1 + +SHELL ["pwsh"] diff --git a/RELEASE.md b/RELEASE.md index 6c5d6b5..f8b28cb 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,2 +1,5 @@ -- Fix `Get-ServiceNowAttachment` returning 0 records when the table name didn't match the table class name, [#188](https://github.com/Snow-Shell/servicenow-powershell/issues/188) -- Update `Add-ServiceNowAttachment` `-Table` and `-ID` parameters with the same 'smarts' as other functions with table name lookup +- Add docker image with each new build and [publish to dockerhub](https://hub.docker.com/repository/docker/gdbarron/servicenow-module). Add the below environment variables to `Get-ServiceNowAuth` for use with docker image, but could be used outside of it as well. + - SNOW_SERVER: the ServiceNow instance, eg. instance.service-now.com + - SNOW_TOKEN: pre-generated oauth token. Provide this or SNOW_USER/SNOW_PASS. + - SNOW_USER: username to connect to SNOW_SERVER + - SNOW_PASS: password for SNOW_USER diff --git a/Readme.md b/Readme.md index 1aa2f5f..32729b1 100644 --- a/Readme.md +++ b/Readme.md @@ -22,6 +22,14 @@ Requires authorization in your ServiceNow tenant. Due to the custom nature of S The ServiceNow module should be installed from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ServiceNow) with `install-module ServiceNow`. +A [docker image](https://hub.docker.com/repository/docker/gdbarron/servicenow-module) is also available with [Microsoft's PowerShell base image](https://hub.docker.com/_/microsoft-powershell) and the ServiceNow module preinstalled. The following environment variables should be used: +- SNOW_SERVER: the ServiceNow instance, eg. instance.service-now.com +- SNOW_TOKEN: pre-generated oauth token. Provide this or SNOW_USER/SNOW_PASS. +- SNOW_USER: username to connect to SNOW_SERVER +- SNOW_PASS: password for SNOW_USER + +When using the docker image, creating a new session is not required. + ### Creating a new session Creating a new session will create a script scoped variable `$ServiceNowSession` which will be used by default in other functions. diff --git a/ServiceNow/Private/Get-ServiceNowAuth.ps1 b/ServiceNow/Private/Get-ServiceNowAuth.ps1 index 124f231..3a65d81 100644 --- a/ServiceNow/Private/Get-ServiceNowAuth.ps1 +++ b/ServiceNow/Private/Get-ServiceNowAuth.ps1 @@ -35,8 +35,7 @@ function Get-ServiceNowAuth { $hashOut.Headers = @{ 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken.GetNetworkCredential().password } - } - else { + } else { $hashOut.Credential = $ServiceNowSession.Credential } @@ -44,18 +43,27 @@ function Get-ServiceNowAuth { $hashOut.Proxy = $ServiceNowSession.Proxy if ( $ServiceNowSession.ProxyCredential ) { $hashOut.ProxyCredential = $ServiceNowSession.ProxyCredential - } - else { + } else { $hashOut.ProxyUseDefaultCredentials = $true } } - } - elseif ( $Connection ) { + } elseif ( $Connection ) { Write-Verbose 'connection' $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) $hashOut.Credential = $Credential $hashOut.Uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri + } elseif ( $env:SNOW_SERVER ) { + $hashOut.Uri = 'https://{0}/api/now' -f $env:SNOW_SERVER + if ( $env:SNOW_TOKEN ) { + $hashOut.Headers = @{ + 'Authorization' = 'Bearer {0}' -f $env:SNOW_TOKEN + } + } elseif ( $env:SNOW_USER -and $env:SNOW_PASS ) { + $hashOut.Credential = New-Object System.Management.Automation.PSCredential($env:SNOW_USER, ($env:SNOW_PASS | ConvertTo-SecureString -AsPlainText -Force)) + } else { + throw 'A ServiceNow server environment variable has been set, but authentication via SNOW_TOKEN or SNOW_USER/SNOW_PASS was not found' + } } else { throw "You must authenticate by either calling the New-ServiceNowSession cmdlet or passing in an Azure Automation connection object" } diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 80ff52c..f70197c 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.2.0' +ModuleVersion = '3.3' # Supported PSEditions # CompatiblePSEditions = @() From f86c5532afcc4159daf0206f694df68a25dc8420 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 21 Jun 2022 18:37:58 +0000 Subject: [PATCH 311/348] Update manifest to 3.3.0 --- CHANGELOG.md | 9 +++++++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e8296d..653d339 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 3.3.0 +- Add docker image with each new build and [publish to dockerhub](https://hub.docker.com/repository/docker/gdbarron/servicenow-module). Add the below environment variables to `Get-ServiceNowAuth` for use with docker image, but could be used outside of it as well. + - SNOW_SERVER: the ServiceNow instance, eg. instance.service-now.com + - SNOW_TOKEN: pre-generated oauth token. Provide this or SNOW_USER/SNOW_PASS. + - SNOW_USER: username to connect to SNOW_SERVER + - SNOW_PASS: password for SNOW_USER + + ## 3.2.0 - Fix `Get-ServiceNowAttachment` returning 0 records when the table name didn't match the table class name, [#188](https://github.com/Snow-Shell/servicenow-powershell/issues/188) - Update `Add-ServiceNowAttachment` `-Table` and `-ID` parameters with the same 'smarts' as other functions with table name lookup @@ -149,3 +157,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index f70197c..8d0ec20 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 05/17/2022 +# Generated on: 06/21/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.3' +ModuleVersion = '3.3.0' # Supported PSEditions # CompatiblePSEditions = @() From cb403ee932970d7639ec0a8ad7398093a43df508 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 18 Jul 2022 09:59:28 -0400 Subject: [PATCH 312/348] New change task, add GraphQL support, custom variable format update (#196) --- RELEASE.md | 8 +- .../Private/Invoke-ServiceNowRestMethod.ps1 | 11 +- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 109 ++++++++------- .../Public/Invoke-ServiceNowGraphQL.ps1 | 118 ++++++++++++++++ .../Public/New-ServiceNowChangeTask.ps1 | 130 ++++++++++++++++++ ServiceNow/Public/New-ServiceNowSession.ps1 | 22 ++- ServiceNow/ServiceNow.psd1 | 4 +- 7 files changed, 334 insertions(+), 68 deletions(-) create mode 100644 ServiceNow/Public/Invoke-ServiceNowGraphQL.ps1 create mode 100644 ServiceNow/Public/New-ServiceNowChangeTask.ps1 diff --git a/RELEASE.md b/RELEASE.md index f8b28cb..8dd560e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,3 @@ -- Add docker image with each new build and [publish to dockerhub](https://hub.docker.com/repository/docker/gdbarron/servicenow-module). Add the below environment variables to `Get-ServiceNowAuth` for use with docker image, but could be used outside of it as well. - - SNOW_SERVER: the ServiceNow instance, eg. instance.service-now.com - - SNOW_TOKEN: pre-generated oauth token. Provide this or SNOW_USER/SNOW_PASS. - - SNOW_USER: username to connect to SNOW_SERVER - - SNOW_PASS: password for SNOW_USER +- Add `New-ServiceNowChangeTask`, [#103](https://github.com/Snow-Shell/servicenow-powershell/issues/103) +- Add GraphQL support including `New-ServiceNowSession -GraphQL` and `Invoke-ServiceNowGraphQL`, the latter is a WIP +- Update custom variable format with `Get-ServiceNowRecord -IncludeCustomVariable`. The new format adds each custom variable as an object property as opposed to an array of hashtables. Old: `$response.CustomVariable.where{$_.name -eq 'mycustvar'}.value`, New: `$response.CustomVariable.mycustvar.value`. Access the new format with `-IncludeCustomVariable -New` \ No newline at end of file diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 026832e..1652313 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -109,9 +109,6 @@ function Invoke-ServiceNowRestMethod { if ($PSCmdlet.PagingParameters.First -ne [uint64]::MaxValue) { $Body['sysparm_limit'] = $PSCmdlet.PagingParameters.First } - # else { - # $Body['sysparm_limit'] = 10 - # } if ($PSCmdlet.PagingParameters.Skip) { $Body['sysparm_offset'] = $PSCmdlet.PagingParameters.Skip @@ -126,12 +123,6 @@ function Invoke-ServiceNowRestMethod { } } - # Populate the query - # else { - # $body['sysparm_query'] = (New-ServiceNowQuery -Filter $Filter -Sort $Sort) - # } - - if ( $Values ) { $Body = $Values | ConvertTo-Json @@ -197,7 +188,7 @@ function Invoke-ServiceNowRestMethod { } # if option to get all records was provided, loop and get them all - if ( $PSCmdlet.PagingParameters.IncludeTotalCount.IsPresent ) { + if ( $PSCmdlet.PagingParameters.IncludeTotalCount ) { $retrieveRecordCount = $totalRecordCount - $PSCmdlet.PagingParameters.Skip if ( $retrieveRecordCount -ne 0 ) { diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 5450908..861a5b0 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -48,6 +48,11 @@ Some records may have associated custom variables, some may not. For instance, an RITM may have custom variables, but the associated tasks may not. A property named 'CustomVariable' will be added to the return object. + When used with -New, you can now get the value with $return.CustomVariable.CustomVarName.Value. + +.PARAMETER New + Used with -IncludeCustomVariable for the new format. + Each property is now added by name with a value of .value. .PARAMETER AsValue Return the underlying value instead of pscustomobject. @@ -107,7 +112,7 @@ Get all change requests, paging 100 at a time. .EXAMPLE - Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -First 5 + Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -New -First 5 Get the first 5 change requests and retrieve custom variable info .EXAMPLE @@ -146,8 +151,7 @@ function Get-ServiceNowRecord { [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true - } - else { + } else { throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' } })] @@ -158,8 +162,7 @@ function Get-ServiceNowRecord { [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true - } - else { + } else { throw 'ParentId must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' } })] @@ -187,6 +190,9 @@ function Get-ServiceNowRecord { [Parameter()] [switch] $IncludeCustomVariable, + [Parameter()] + [switch] $New, + [Parameter()] [switch] $AsValue, @@ -235,8 +241,7 @@ function Get-ServiceNowRecord { } $idFilter = @('sys_id', '-eq', $ID) - } - else { + } else { if ( -not $thisTable ) { # get table name from prefix if only Id was provided $idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() @@ -251,8 +256,7 @@ function Get-ServiceNowRecord { if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter - } - else { + } else { $invokeParams.Filter = $idFilter } @@ -264,15 +268,13 @@ function Get-ServiceNowRecord { if ( $ParentID ) { if ( $ParentID -match '^[a-zA-Z0-9]{32}$' ) { $parentIdFilter = @('parent.sys_id', '-eq', $ParentID) - } - else { + } else { $parentIdFilter = @('parent.number', '-eq', $ParentID) } if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', $parentIdFilter - } - else { + } else { $invokeParams.Filter = $parentIdFilter } } @@ -286,8 +288,7 @@ function Get-ServiceNowRecord { if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', @($thisTable.DescriptionField, '-like', $Description) - } - else { + } else { $invokeParams.Filter = @($thisTable.DescriptionField, '-like', $Description) } } @@ -313,10 +314,6 @@ function Get-ServiceNowRecord { if ( $IncludeCustomVariable ) { - # suppress warning when getting total count - $existingWarning = $WarningPreference - $WarningPreference = 'SilentlyContinue' - # for each record, get the variable names and then get the variable values foreach ($record in $result) { @@ -325,54 +322,70 @@ function Get-ServiceNowRecord { Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22,26') Property = 'sc_item_option.item_option_new.name', 'sc_item_option.value', 'sc_item_option.item_option_new.type', 'sc_item_option.item_option_new.question_text' IncludeTotalCount = $true + ServiceNowSession = $ServiceNowSession } - $customVarsOut = Get-ServiceNowRecord @customVarParams - - $record | Add-Member @{ - 'CustomVariable' = $customVarsOut | Select-Object -Property ` - @{ - 'n' = 'Name' - 'e' = { $_.'sc_item_option.item_option_new.name' } - }, - @{ - 'n' = 'Value' - 'e' = { $_.'sc_item_option.value' } - }, - @{ - 'n' = 'DisplayName' - 'e' = { $_.'sc_item_option.item_option_new.question_text' } - }, - @{ - 'n' = 'Type' - 'e' = { $_.'sc_item_option.item_option_new.type' } + # suppress warning when getting total count + $customVarsOut = Get-ServiceNowRecord @customVarParams -WarningAction SilentlyContinue + + if ( $New ) { + + $record | Add-Member @{ + 'CustomVariable' = [pscustomobject]@{} + } + foreach ($var in $customVarsOut) { + $record.CustomVariable | Add-Member @{ + $var.'sc_item_option.item_option_new.name' = @{ + Value = $var.'sc_item_option.value' + DisplayName = $var.'sc_item_option.item_option_new.question_text' + Type = $var.'sc_item_option.item_option_new.type' + } + } + } + } else { + + Write-Warning 'The format for custom variables will soon change. Start using -New with -IncludeCustomVariable to preview.' + + $record | Add-Member @{ + 'CustomVariable' = $customVarsOut | Select-Object -Property ` + @{ + 'n' = 'Name' + 'e' = { $_.'sc_item_option.item_option_new.name' } + }, + @{ + 'n' = 'Value' + 'e' = { $_.'sc_item_option.value' } + }, + @{ + 'n' = 'DisplayName' + 'e' = { $_.'sc_item_option.item_option_new.question_text' } + }, + @{ + 'n' = 'Type' + 'e' = { $_.'sc_item_option.item_option_new.type' } + } } } + if ( $addedSysIdProp ) { $record | Select-Object -Property * -ExcludeProperty sys_id - } - else { + } else { $record } } - $WarningPreference = $existingWarning - - } - else { + } else { # format the results if ( $Property ) { if ( $Property.Count -eq 1 -and $AsValue ) { $propName = $result | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' } | Select-Object -exp Name $result | Select-Object -ExpandProperty $propName - } - else { + } else { $result } - } - else { + } else { if ($thisTable.Type) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $thisTable.Type) } } diff --git a/ServiceNow/Public/Invoke-ServiceNowGraphQL.ps1 b/ServiceNow/Public/Invoke-ServiceNowGraphQL.ps1 new file mode 100644 index 0000000..79fe2f5 --- /dev/null +++ b/ServiceNow/Public/Invoke-ServiceNowGraphQL.ps1 @@ -0,0 +1,118 @@ +<# +.SYNOPSIS + Retrieve or update data via GraphQL - still a work in progress :) + +.DESCRIPTION + Retrieve or update data via GraphQL. + Ensure you create a new session with -GraphQL. + +.PARAMETER Operation + Allowed values are 'query' or 'mutation'. + The default is query. + +.PARAMETER Application + Application namespace for your API + +.PARAMETER Schema + Schema namespace for your API + +.PARAMETER Query + Inner query string. Operation, application, and schema will be added automatically. + +.PARAMETER Variable + Currently only supported with -Raw. + Ensure the query includes the operation, application, and schema. + +.PARAMETER Raw + Provide the server response as is instead of parsing out the application, schema, and service names. + +.PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + +.PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. + +.EXAMPLE + Invoke-ServiceNowGraphQL -Application myapp -Schema incident -Query 'findById (id: "INC0010001") {sys_id {value} description {value}}' + + Perform a query + +.OUTPUTS + PSCustomObject + +.LINK + https://docs.servicenow.com/bundle/sandiego-application-development/page/integrate/graphql/concept/scripted-graph-ql.html +#> +function Invoke-ServiceNowGraphQL { + + [OutputType([System.Management.Automation.PSCustomObject])] + [CmdletBinding()] + + Param ( + [Parameter()] + [ValidateSet('query', 'mutation')] + [string] $Operation = 'query', + + [Parameter(Mandatory)] + [string] $Application, + + [Parameter(Mandatory)] + [string] $Schema, + + [Parameter(Mandatory)] + [string] $Query, + + [Parameter()] + [string] $Variable, + + [Parameter()] + [switch] $Raw, + + [Parameter()] + [hashtable] $Connection, + + [Parameter()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession + ) + + begin { + + Write-Warning 'This function is in beta and subject to change. Please please feedback/enhancements at https://github.com/Snow-Shell/servicenow-powershell/issues.' + + if ( $Raw ) { + $fullQuery = $Query + } else { + $fullQuery = ('{0} {{ {1} {{ {2} {{ {3} }}}}}}' -f $Operation, $Application, $Schema, $Query) + } + + $params = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession + + $params.Method = 'Post' + $params.ContentType = 'application/json' + $params.UseBasicParsing = $true + + $body = @{ + 'query' = $fullQuery + } + + if ( $Variable ) { + $body.variables = $Variable + } + + $params.Body = $body | ConvertTo-Json -Compress + } + + process { + Write-Verbose ($params | ConvertTo-Json) + $result = Invoke-RestMethod @params + + if ( $Raw ) { + $result + } else { + $serviceName = $Query -replace '^(\w*).*', '$1' + if ( $result.data.$Application.$Schema.$serviceName ) { + $result.data.$Application.$Schema.$serviceName + } + } + } +} diff --git a/ServiceNow/Public/New-ServiceNowChangeTask.ps1 b/ServiceNow/Public/New-ServiceNowChangeTask.ps1 new file mode 100644 index 0000000..a879cd5 --- /dev/null +++ b/ServiceNow/Public/New-ServiceNowChangeTask.ps1 @@ -0,0 +1,130 @@ +function New-ServiceNowChangeTask { + <# + .SYNOPSIS + Create a new change task + + .DESCRIPTION + Create a new change task + + .PARAMETER ChangeRequest + sys_id or number of parent change request + + .PARAMETER ShortDescription + Short description of the change task + + .PARAMETER Description + Long description of the change task + + .PARAMETER AssignmentGroup + sys_id or name of the assignment group + + .PARAMETER AssignedTo + sys_id or name of the assigned user + + .PARAMETER CustomField + Other key/value pairs to create the task which are not one of the existing parameters + + .PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + + .PARAMETER PassThru + Return the newly created item details + + .EXAMPLE + New-ServiceNowChangeTask -ChangeRequest RITM0010001 -ShortDescription 'New PS change request' -Description 'This change request was created from Powershell' -AssignmentGroup ServiceDesk + + Create a new task + + .EXAMPLE + New-ServiceNowChangeTask -ShortDescription 'New' -Description 'Longer description' -CustomField @{'impact'='3'} + + Create a new task with additional fields + #> + + [CmdletBinding(SupportsShouldProcess)] + + Param( + + [Parameter(Mandatory)] + [string] $ShortDescription, + + [parameter(Mandatory)] + [string] $Description, + + [Parameter()] + [string] $ChangeRequest, + + [Parameter()] + [string] $AssignmentGroup, + + [Parameter()] + [string] $AssignedTo, + + [Parameter()] + [hashtable] $CustomField, + + [Parameter()] + [Hashtable] $Connection, + + [Parameter()] + [hashtable] $ServiceNowSession = $script:ServiceNowSession, + + [Parameter()] + [switch] $PassThru + ) + + begin { + $createValues = @{} + } + + process { + + switch ($PSBoundParameters.Keys) { + 'ChangeRequest' { + $createValues.parent = $ChangeRequest + } + + 'ShortDescription' { + $createValues.short_description = $ShortDescription + } + + 'Description' { + $createValues.description = $Description + } + + 'AssignmentGroup' { + $createValues.assignment_group = $AssignmentGroup + } + + 'AssignedTo' { + $createValues.assignment_to = $AssignmentTo + } + } + + $CustomField.GetEnumerator() | ForEach-Object { + if ( $createValues.($_.Key) ) { + Write-Warning ('Custom field {0} has already been added via parameter' -f $_.Key) + } else { + $createValues.Add($_.Key, $_.Value) + } + } + + $params = @{ + Method = 'Post' + Table = 'change_task' + Values = $createValues + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + + If ( $PSCmdlet.ShouldProcess($ShortDescription, 'Create new change task') ) { + $response = Invoke-ServiceNowRestMethod @params + If ( $PassThru ) { + $response.PSObject.TypeNames.Insert(0, "ServiceNow.ChangeTask") + $response + } + } + } + + end {} +} diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index d5fd336..002576a 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -29,6 +29,9 @@ Credential of user who can access Proxy. If not provided, the current user will .PARAMETER ApiVersion Specific API version to use. The default is the latest. +.PARAMETER GraphQL +Use GraphQL instead of REST calls + .PARAMETER GetAllTable Populate $ServiceNowTable with data from all tables the user has access to @@ -38,15 +41,21 @@ This is useful if you want to have multiple sessions with different api versions .EXAMPLE New-ServiceNowSession -Url tenant.domain.com -Credential $mycred -Create a session using basic authentication and save it to a script-scoped variable +Create a new session using basic authentication and save it as the default. + +.EXAMPLE +New-ServiceNowSession -Url tenant.domain.com -Credential $mycred -GraphQL + +Create a new session using basic authentication and save it as the default. +Use GraphQL instead of REST. .EXAMPLE New-ServiceNowSession -Url tenant.domain.com -Credential $mycred -ClientCredential $myClientCred -Create a session using OAuth and save it to a script-scoped variable +Create a session using OAuth and save it as the default .EXAMPLE New-ServiceNowSession -Url tenant.domain.com -AccessToken 'asdfasd9f87adsfkksk3nsnd87g6s' -Create a session with an existing access token and save it to a script-scoped variable +Create a session with an existing access token and save it as the default .EXAMPLE $session = New-ServiceNowSession -Url tenant.domain.com -Credential $mycred -ClientCredential $myClientCred -PassThru @@ -107,6 +116,9 @@ function New-ServiceNowSession { [Parameter()] [switch] $GetAllTable, + [Parameter()] + [switch] $GraphQL, + [Parameter()] [switch] $PassThru ) @@ -125,6 +137,10 @@ function New-ServiceNowSession { BaseUri = ('https://{0}/api/now{1}' -f $Url, $version) } + if ( $GraphQL ) { + $newSession.BaseUri = ('https://{0}/api/now/graphql' -f $Url) + } + if ( $PSBoundParameters.ContainsKey('Proxy') ) { $newSession.Add('Proxy', $Proxy) if ( $PSBoundParameters.ContainsKey('ProxyCredential') ) { diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 8d0ec20..070464f 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.3.0' +ModuleVersion = '3.4' # Supported PSEditions # CompatiblePSEditions = @() @@ -82,7 +82,7 @@ FunctionsToExport = 'Get-ServiceNowRecordInterim', 'New-ServiceNowConfigurationI 'Remove-ServiceNowAttachment', 'Remove-ServiceNowRecord', 'Update-ServiceNowChangeRequest', 'Update-ServiceNowIncident', 'Update-ServiceNowRequestedItem', 'Update-ServiceNowRecord', - 'Export-ServiceNowRecord' + 'Export-ServiceNowRecord', 'Invoke-ServiceNowGraphQL', 'New-ServiceNowChangeTask' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() From 2a2e0cbd6f5aac36335df37aa304a5e43f7ddab8 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 18 Jul 2022 14:01:26 +0000 Subject: [PATCH 313/348] Update manifest to 3.4.0 --- CHANGELOG.md | 6 ++++++ ServiceNow/ServiceNow.psd1 | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 653d339..ac73486 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 3.4.0 +- Add `New-ServiceNowChangeTask`, [#103](https://github.com/Snow-Shell/servicenow-powershell/issues/103) +- Add GraphQL support including `New-ServiceNowSession -GraphQL` and `Invoke-ServiceNowGraphQL`, the latter is a WIP +- Update custom variable format with `Get-ServiceNowRecord -IncludeCustomVariable`. The new format adds each custom variable as an object property as opposed to an array of hashtables. Old: `$response.CustomVariable.where{$_.name -eq 'mycustvar'}.value`, New: `$response.CustomVariable.mycustvar.value`. Access the new format with `-IncludeCustomVariable -New` + ## 3.3.0 - Add docker image with each new build and [publish to dockerhub](https://hub.docker.com/repository/docker/gdbarron/servicenow-module). Add the below environment variables to `Get-ServiceNowAuth` for use with docker image, but could be used outside of it as well. - SNOW_SERVER: the ServiceNow instance, eg. instance.service-now.com @@ -158,3 +163,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 070464f..e0dd510 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 06/21/2022 +# Generated on: 07/18/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.4' +ModuleVersion = '3.4.0' # Supported PSEditions # CompatiblePSEditions = @() @@ -82,7 +82,8 @@ FunctionsToExport = 'Get-ServiceNowRecordInterim', 'New-ServiceNowConfigurationI 'Remove-ServiceNowAttachment', 'Remove-ServiceNowRecord', 'Update-ServiceNowChangeRequest', 'Update-ServiceNowIncident', 'Update-ServiceNowRequestedItem', 'Update-ServiceNowRecord', - 'Export-ServiceNowRecord', 'Invoke-ServiceNowGraphQL', 'New-ServiceNowChangeTask' + 'Export-ServiceNowRecord', 'Invoke-ServiceNowGraphQL', + 'New-ServiceNowChangeTask' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() From cd20aadb14f7627835b9ed803ec82149bf4d47cd Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 10 Aug 2022 23:14:29 -0400 Subject: [PATCH 314/348] Create ask_question.md --- .github/ISSUE_TEMPLATE/ask_question.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/ask_question.md diff --git a/.github/ISSUE_TEMPLATE/ask_question.md b/.github/ISSUE_TEMPLATE/ask_question.md new file mode 100644 index 0000000..6fc432e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ask_question.md @@ -0,0 +1,9 @@ +--- +name: Ask a question +about: How can we help? + +--- + + From 4ccb079608dfb6d0a7628d6fec3bbdcc3e787e46 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 27 Sep 2022 21:15:03 -0400 Subject: [PATCH 315/348] pscustomobject for custom vars (#206) --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 861a5b0..0991ea6 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -335,7 +335,7 @@ function Get-ServiceNowRecord { } foreach ($var in $customVarsOut) { $record.CustomVariable | Add-Member @{ - $var.'sc_item_option.item_option_new.name' = @{ + $var.'sc_item_option.item_option_new.name' = [pscustomobject] @{ Value = $var.'sc_item_option.value' DisplayName = $var.'sc_item_option.item_option_new.question_text' Type = $var.'sc_item_option.item_option_new.type' From a4e665823462f1a5b6dd01bbbd6221fd456118f8 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 27 Sep 2022 21:17:25 -0400 Subject: [PATCH 316/348] Update RELEASE.md --- RELEASE.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 8dd560e..63864cf 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,3 +1 @@ -- Add `New-ServiceNowChangeTask`, [#103](https://github.com/Snow-Shell/servicenow-powershell/issues/103) -- Add GraphQL support including `New-ServiceNowSession -GraphQL` and `Invoke-ServiceNowGraphQL`, the latter is a WIP -- Update custom variable format with `Get-ServiceNowRecord -IncludeCustomVariable`. The new format adds each custom variable as an object property as opposed to an array of hashtables. Old: `$response.CustomVariable.where{$_.name -eq 'mycustvar'}.value`, New: `$response.CustomVariable.mycustvar.value`. Access the new format with `-IncludeCustomVariable -New` \ No newline at end of file +- Update `Get-ServiceNowRecord` to ensure new custom variable format is pscustomobject, [#205](https://github.com/Snow-Shell/servicenow-powershell/issues/205) From 19e38411ee978aff2581eb06f5cdb2827042a289 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 28 Sep 2022 01:17:57 +0000 Subject: [PATCH 317/348] Update manifest to 3.4.1 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac73486..e52eb9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.4.1 +- Update `Get-ServiceNowRecord` to ensure new custom variable format is pscustomobject, [#205](https://github.com/Snow-Shell/servicenow-powershell/issues/205) + + ## 3.4.0 - Add `New-ServiceNowChangeTask`, [#103](https://github.com/Snow-Shell/servicenow-powershell/issues/103) - Add GraphQL support including `New-ServiceNowSession -GraphQL` and `Invoke-ServiceNowGraphQL`, the latter is a WIP @@ -164,3 +168,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index e0dd510..301a1d3 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 07/18/2022 +# Generated on: 09/28/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.4.0' +ModuleVersion = '3.4.1' # Supported PSEditions # CompatiblePSEditions = @() From 7cd52f636f7a9f1cc1048186dc6f45edec284c71 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 17 Oct 2022 20:12:07 -0400 Subject: [PATCH 318/348] fix hashtable key add error (#208) --- ServiceNow/Private/Get-ServiceNowAuth.ps1 | 2 +- .../Public/Add-ServiceNowAttachment.ps1 | 49 ++++++++++++------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/ServiceNow/Private/Get-ServiceNowAuth.ps1 b/ServiceNow/Private/Get-ServiceNowAuth.ps1 index 3a65d81..31c6ae6 100644 --- a/ServiceNow/Private/Get-ServiceNowAuth.ps1 +++ b/ServiceNow/Private/Get-ServiceNowAuth.ps1 @@ -70,6 +70,6 @@ function Get-ServiceNowAuth { } end { - $hashOut + $hashOut.Clone() } } diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 805fa8e..4c553d4 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -86,7 +86,11 @@ Function Add-ServiceNowAttachment { [Parameter(Mandatory)] [ValidateScript( { - Test-Path $_ + if ( Test-Path $_ ) { + $true + } else { + throw 'One or more files do not exist' + } })] [string[]] $File, @@ -105,7 +109,12 @@ Function Add-ServiceNowAttachment { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - begin {} + begin { + $auth = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession + $invokeRestMethodSplat = $auth + $invokeRestMethodSplat.UseBasicParsing = $true + $invokeRestMethodSplat.Method = 'POST' + } process { @@ -153,32 +162,34 @@ Function Add-ServiceNowAttachment { $thisSysId = $tableRecord.sys_id } - $auth = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession - ForEach ($Object in $File) { - $FileData = Get-ChildItem $Object -ErrorAction Stop - If (-not $ContentType) { + foreach ($thisFile in $File) { + + $thisFileObject = Get-ChildItem $thisFile + + If ( -not $PSBoundParameters.ContainsKey('ContentType') ) { # Thanks to https://github.com/samuelneff/MimeTypeMap/blob/master/MimeTypeMap.cs from which # MimeTypeMap.json was adapted - $ContentTypeHash = ConvertFrom-Json (Get-Content "$PSScriptRoot\..\config\MimeTypeMap.json" -Raw) + $contentTypes = ConvertFrom-Json (Get-Content "$PSScriptRoot\..\config\MimeTypeMap.json" -Raw) + + $Extension = [IO.Path]::GetExtension($thisFileObject.FullName) + $ContentType = $contentTypes.$Extension - $Extension = [IO.Path]::GetExtension($FileData.FullName) - $ContentType = $ContentTypeHash.$Extension + if ( -not $ContentType ) { + Write-Error ('Content type not found for {0}, the file will not be uploaded' -f $thisFileObject.FullName) + Continue + } } # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot - # $Uri = "{0}/file?table_name={1}&table_sys_id={2}&file_name={3}" -f $ApiUrl, $Table, $TableSysID, $FileData.Name - $invokeRestMethodSplat = $auth - $invokeRestMethodSplat.Uri += '/attachment/file?table_name={0}&table_sys_id={1}&file_name={2}' -f $thisTableName, $thisSysId, $FileData.Name - $invokeRestMethodSplat.Headers += @{'Content-Type' = $ContentType } - $invokeRestMethodSplat.UseBasicParsing = $true - $invokeRestMethodSplat += @{ - Method = 'POST' - InFile = $FileData.FullName - } + $invokeRestMethodSplat.Uri = '{0}/attachment/file?table_name={1}&table_sys_id={2}&file_name={3}' -f $auth.Uri, $thisTableName, $thisSysId, $thisFileObject.Name + $invokeRestMethodSplat.ContentType = $ContentType + $invokeRestMethodSplat.InFile = $thisFileObject.FullName + + If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $thisTableName, $thisSysId), ('Add attachment {0}' -f $thisFileObject.FullName))) { - If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $thisTableName, $thisSysId), ('Add attachment {0}' -f $FileData.FullName))) { Write-Verbose ($invokeRestMethodSplat | ConvertTo-Json) + $response = Invoke-WebRequest @invokeRestMethodSplat if ( $response.Content ) { From 462158ae9fe84df8a1ba63bd00c323bfca0fb34b Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 18 Oct 2022 18:55:03 -0400 Subject: [PATCH 319/348] Update RELEASE.md --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 63864cf..caac832 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1 +1 @@ -- Update `Get-ServiceNowRecord` to ensure new custom variable format is pscustomobject, [#205](https://github.com/Snow-Shell/servicenow-powershell/issues/205) +- Fix `Add-ServiceNowAttachment` content type error when attempting to add multiple files, [#207](https://github.com/Snow-Shell/servicenow-powershell/issues/207) From 453bac0a7d1c6e8602d799e7a60fbafafb2a0239 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Tue, 18 Oct 2022 22:55:39 +0000 Subject: [PATCH 320/348] Update manifest to 3.4.2 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e52eb9f..361b23c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.4.2 +- Fix `Add-ServiceNowAttachment` content type error when attempting to add multiple files, [#207](https://github.com/Snow-Shell/servicenow-powershell/issues/207) + + ## 3.4.1 - Update `Get-ServiceNowRecord` to ensure new custom variable format is pscustomobject, [#205](https://github.com/Snow-Shell/servicenow-powershell/issues/205) @@ -169,3 +173,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 301a1d3..32e324c 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 09/28/2022 +# Generated on: 10/18/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.4.1' +ModuleVersion = '3.4.2' # Supported PSEditions # CompatiblePSEditions = @() From 71ae6ca824924b85fc76254b5fbac0a09a72e61d Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 14 Dec 2022 10:50:04 -0500 Subject: [PATCH 321/348] Resolve underlying reference value with custom variables (#221) --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 62 +++++++++++++++------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 0991ea6..022c824 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -151,7 +151,8 @@ function Get-ServiceNowRecord { [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true - } else { + } + else { throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' } })] @@ -162,7 +163,8 @@ function Get-ServiceNowRecord { [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true - } else { + } + else { throw 'ParentId must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' } })] @@ -241,7 +243,8 @@ function Get-ServiceNowRecord { } $idFilter = @('sys_id', '-eq', $ID) - } else { + } + else { if ( -not $thisTable ) { # get table name from prefix if only Id was provided $idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() @@ -256,7 +259,8 @@ function Get-ServiceNowRecord { if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter - } else { + } + else { $invokeParams.Filter = $idFilter } @@ -268,13 +272,15 @@ function Get-ServiceNowRecord { if ( $ParentID ) { if ( $ParentID -match '^[a-zA-Z0-9]{32}$' ) { $parentIdFilter = @('parent.sys_id', '-eq', $ParentID) - } else { + } + else { $parentIdFilter = @('parent.number', '-eq', $ParentID) } if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', $parentIdFilter - } else { + } + else { $invokeParams.Filter = $parentIdFilter } } @@ -288,7 +294,8 @@ function Get-ServiceNowRecord { if ( $invokeParams.Filter ) { $invokeParams.Filter = $invokeParams.Filter, 'and', @($thisTable.DescriptionField, '-like', $Description) - } else { + } + else { $invokeParams.Filter = @($thisTable.DescriptionField, '-like', $Description) } } @@ -317,10 +324,14 @@ function Get-ServiceNowRecord { # for each record, get the variable names and then get the variable values foreach ($record in $result) { + $recordSysId = if ($DisplayValue -eq 'all') { $record.sys_id.value } else { $record.sys_id } + + # YES_NO = 1; MULTI_LINE_TEXT = 2; MULTIPLE_CHOICE = 3; NUMERIC_SCALE = 4; SELECT_BOX = 5; SINGLE_LINE_TEXT = 6; CHECKBOX = 7; REFERENCE = 8; DATE = 9; DATE_TIME = 10; LABEL = 11; BREAK = 12; MACRO = 14; UI_PAGE = 15; WIDE_SINGLE_LINE_TEXT = 16; MACRO_WITH_LABEL = 17; LOOKUP_SELECT_BOX = 18; CONTAINER_START = 19; CONTAINER_END = 20; LIST_COLLECTOR = 21; LOOKUP_MULTIPLE_CHOICE = 22; HTML = 23; SPLIT = 24; MASKED = 25; + $customVarParams = @{ Table = 'sc_item_option_mtom' - Filter = @('request_item', '-eq', $record.sys_id), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22,26') - Property = 'sc_item_option.item_option_new.name', 'sc_item_option.value', 'sc_item_option.item_option_new.type', 'sc_item_option.item_option_new.question_text' + Filter = @('request_item', '-eq', $recordSysId), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22,26') + Property = 'sc_item_option.item_option_new.name', 'sc_item_option.value', 'sc_item_option.item_option_new.type', 'sc_item_option.item_option_new.question_text', 'sc_item_option.item_option_new.reference' IncludeTotalCount = $true ServiceNowSession = $ServiceNowSession } @@ -333,16 +344,23 @@ function Get-ServiceNowRecord { $record | Add-Member @{ 'CustomVariable' = [pscustomobject]@{} } + foreach ($var in $customVarsOut) { - $record.CustomVariable | Add-Member @{ - $var.'sc_item_option.item_option_new.name' = [pscustomobject] @{ - Value = $var.'sc_item_option.value' - DisplayName = $var.'sc_item_option.item_option_new.question_text' - Type = $var.'sc_item_option.item_option_new.type' - } + $newVar = [pscustomobject] @{ + Value = $var.'sc_item_option.value' + DisplayName = $var.'sc_item_option.item_option_new.question_text' + Type = $var.'sc_item_option.item_option_new.type' + } + + # show the underlying value if the option is a reference type + if ($newVar.Type -eq 'Reference' ) { + $newVar.Value = (Get-ServiceNowRecord -Table $var.'sc_item_option.item_option_new.reference' -ID $var.'sc_item_option.value' -Property name -AsValue -ServiceNowSession $ServiceNowSession) } + + $record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.name' = $newVar } } - } else { + } + else { Write-Warning 'The format for custom variables will soon change. Start using -New with -IncludeCustomVariable to preview.' @@ -370,22 +388,26 @@ function Get-ServiceNowRecord { if ( $addedSysIdProp ) { $record | Select-Object -Property * -ExcludeProperty sys_id - } else { + } + else { $record } } - } else { + } + else { # format the results if ( $Property ) { if ( $Property.Count -eq 1 -and $AsValue ) { $propName = $result | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' } | Select-Object -exp Name $result | Select-Object -ExpandProperty $propName - } else { + } + else { $result } - } else { + } + else { if ($thisTable.Type) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $thisTable.Type) } } From e6ff5ebf76ef88d31189148395ca6c7770f3ac96 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sat, 17 Dec 2022 08:33:39 -0500 Subject: [PATCH 322/348] Update RELEASE.md --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index caac832..c926f6a 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1 +1 @@ -- Fix `Add-ServiceNowAttachment` content type error when attempting to add multiple files, [#207](https://github.com/Snow-Shell/servicenow-powershell/issues/207) +- `Get-ServiceNowRecord`, custom variables of type Reference providing sysid instead of actual value, [#218](https://github.com/Snow-Shell/servicenow-powershell/issues/218) From 71e052ee831f0aecce139594b9c97838e8554548 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sat, 17 Dec 2022 13:34:13 +0000 Subject: [PATCH 323/348] Update manifest to 3.4.3 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 361b23c..f6f736b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.4.3 +- `Get-ServiceNowRecord`, custom variables of type Reference providing sysid instead of actual value, [#218](https://github.com/Snow-Shell/servicenow-powershell/issues/218) + + ## 3.4.2 - Fix `Add-ServiceNowAttachment` content type error when attempting to add multiple files, [#207](https://github.com/Snow-Shell/servicenow-powershell/issues/207) @@ -174,3 +178,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 32e324c..4f98ee9 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Sam Martin Rick Arroues Greg Brownstein # -# Generated on: 10/18/2022 +# Generated on: 12/17/2022 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.4.2' +ModuleVersion = '3.4.3' # Supported PSEditions # CompatiblePSEditions = @() From 96c1f59e5b648c5ca8d50ce0dec8d3d98b301c21 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sat, 25 Feb 2023 08:46:56 -0500 Subject: [PATCH 324/348] fix unknown table update (#231) --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 73 +++++++------------ ServiceNow/Public/Update-ServiceNowRecord.ps1 | 58 +++++++++++---- ServiceNow/ServiceNow.psd1 | 2 +- ServiceNow/ServiceNow.psm1 | 6 +- 4 files changed, 73 insertions(+), 66 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 022c824..40063d6 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -50,10 +50,6 @@ A property named 'CustomVariable' will be added to the return object. When used with -New, you can now get the value with $return.CustomVariable.CustomVarName.Value. -.PARAMETER New - Used with -IncludeCustomVariable for the new format. - Each property is now added by name with a value of .value. - .PARAMETER AsValue Return the underlying value instead of pscustomobject. Only valid when the Property parameter is set to 1 item. @@ -112,7 +108,7 @@ Get all change requests, paging 100 at a time. .EXAMPLE - Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -New -First 5 + Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -First 5 Get the first 5 change requests and retrieve custom variable info .EXAMPLE @@ -207,6 +203,10 @@ function Get-ServiceNowRecord { begin { + if ( $New ) { + Write-Warning '-New is now deprecated and the new format is the default' + } + $invokeParams = @{ Filter = $Filter Property = $Property @@ -313,12 +313,17 @@ function Get-ServiceNowRecord { # should use Get-ServiceNowAttachment, but put this here for ease of access if ( $thisTable.Name -eq 'attachment' ) { Write-Warning 'For attachments, use Get-ServiceNowAttachment' - $invokeParams.Remove('Table') | Out-Null + $null = $invokeParams.Remove('Table') $invokeParams.UriLeaf = '/attachment' } $result = Invoke-ServiceNowRestMethod @invokeParams + # custom tables do not have a sys_class_name property, add it + if ( -not $Property -and $result.PSObject.Properties.name -notcontains 'sys_class_name' ) { + $result | Add-Member @{'sys_class_name' = $Table } + } + if ( $IncludeCustomVariable ) { # for each record, get the variable names and then get the variable values @@ -339,53 +344,25 @@ function Get-ServiceNowRecord { # suppress warning when getting total count $customVarsOut = Get-ServiceNowRecord @customVarParams -WarningAction SilentlyContinue - if ( $New ) { + $record | Add-Member @{ + 'CustomVariable' = [pscustomobject]@{} + } - $record | Add-Member @{ - 'CustomVariable' = [pscustomobject]@{} + foreach ($var in $customVarsOut) { + $newVar = [pscustomobject] @{ + Value = $var.'sc_item_option.value' + DisplayName = $var.'sc_item_option.item_option_new.question_text' + Type = $var.'sc_item_option.item_option_new.type' } - foreach ($var in $customVarsOut) { - $newVar = [pscustomobject] @{ - Value = $var.'sc_item_option.value' - DisplayName = $var.'sc_item_option.item_option_new.question_text' - Type = $var.'sc_item_option.item_option_new.type' - } - - # show the underlying value if the option is a reference type - if ($newVar.Type -eq 'Reference' ) { - $newVar.Value = (Get-ServiceNowRecord -Table $var.'sc_item_option.item_option_new.reference' -ID $var.'sc_item_option.value' -Property name -AsValue -ServiceNowSession $ServiceNowSession) - } - - $record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.name' = $newVar } + # show the underlying value if the option is a reference type + if ($newVar.Type -eq 'Reference' ) { + $newVar.Value = (Get-ServiceNowRecord -Table $var.'sc_item_option.item_option_new.reference' -ID $var.'sc_item_option.value' -Property name -AsValue -ServiceNowSession $ServiceNowSession) } - } - else { - Write-Warning 'The format for custom variables will soon change. Start using -New with -IncludeCustomVariable to preview.' - - $record | Add-Member @{ - 'CustomVariable' = $customVarsOut | Select-Object -Property ` - @{ - 'n' = 'Name' - 'e' = { $_.'sc_item_option.item_option_new.name' } - }, - @{ - 'n' = 'Value' - 'e' = { $_.'sc_item_option.value' } - }, - @{ - 'n' = 'DisplayName' - 'e' = { $_.'sc_item_option.item_option_new.question_text' } - }, - @{ - 'n' = 'Type' - 'e' = { $_.'sc_item_option.item_option_new.type' } - } - } + $record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.name' = $newVar } } - if ( $addedSysIdProp ) { $record | Select-Object -Property * -ExcludeProperty sys_id } @@ -400,8 +377,8 @@ function Get-ServiceNowRecord { # format the results if ( $Property ) { if ( $Property.Count -eq 1 -and $AsValue ) { - $propName = $result | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' } | Select-Object -exp Name - $result | Select-Object -ExpandProperty $propName + $propName = $result | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' } | Select-Object -ExpandProperty Name + $result.$propName } else { $result diff --git a/ServiceNow/Public/Update-ServiceNowRecord.ps1 b/ServiceNow/Public/Update-ServiceNowRecord.ps1 index 49071f8..a4748b3 100644 --- a/ServiceNow/Public/Update-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRecord.ps1 @@ -9,7 +9,7 @@ Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. You can also provide any table name ad hoc. -.PARAMETER Id +.PARAMETER ID Either the record sys_id or number. If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. @@ -26,11 +26,23 @@ ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. .EXAMPLE - Update-ServiceNowRecord -Table incident -Id 'INC0010001' -Values @{State = 'Closed'} - Close an incident record + Update-ServiceNowRecord -ID 'INC0010001' -Values @{State = 'Closed'} + Update a record by number. The table name will be looked up based on the prefix. + +.EXAMPLE + Update-ServiceNowRecord -Table 'change_request' -ID 'CHG0010001' -Values @{'work_notes' = 'my notes'} + Update a record by number. The table name is provided directly as the table lookup is different, 'Change Request' as opposed to 'change_request'. + +.EXAMPLE + Update-ServiceNowRecord -Table incident -ID '13378afb-97a6-451a-b1ec-2c9e85313188' -Values @{State = 'Closed'} + Update a record by table name and sys_id. + +.EXAMPLE + Get-ServiceNowRecord INC0000001 | Update-ServiceNowRecord -Values @{work_notes = "Updated by PowerShell"} + Update details piping an existing object. You do not need to specify the table or ID for the update. .INPUTS - Table, Id + Table, ID .OUTPUTS PSCustomObject, if PassThru is provided @@ -66,10 +78,14 @@ function Update-ServiceNowRecord { process { - if ( $Table -and ($ID -match '[a-zA-Z0-9]{32}') ) { - # we already have table name and sys_id, no more to do before update - $tableName = $Table + if ( $ID -match '[a-zA-Z0-9]{32}' ) { $sysId = $ID + if ( $Table ) { + $tableName = $Table + } + else { + Write-Error 'Providing a sys_id for -ID requires a value for -Table' + } } else { # get needed details, table name and sys_id, for update @@ -86,28 +102,40 @@ function Update-ServiceNowRecord { $thisRecord = Get-ServiceNowRecord @getParams - if ( $thisRecord ) { - $tableName = $thisRecord.sys_class_name - $sysId = $thisRecord.sys_id + if ( -not $thisRecord ) { + Write-Error ('Record not found for ID ''{0}''' -f $ID) + continue + } + + # if the table name was provided, use it + # otherwise use the table name we retrieved which may or may not work + if ( $Table ) { + $tableName = $Table } else { - Write-Error ('Record not found for Id ''{0}''' -f $ID) - continue + $tableName = $thisRecord.sys_class_name } + $sysId = $thisRecord.sys_id + } + + $newTableName = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $tableName.ToLower() -or $_.ClassName.ToLower() -eq $tableName.ToLower() } | Select-Object -ExpandProperty Name + if ( -not $newTableName ) { + # we aren't aware of this table in our config so use as is + $newTableName = $tableName } $params = @{ Method = 'Patch' - Table = $tableName + Table = $newTableName SysId = $sysId Values = $Values Connection = $Connection ServiceNowSession = $ServiceNowSession } - If ($PSCmdlet.ShouldProcess("$tableName $sysId", 'Update values')) { + If ($PSCmdlet.ShouldProcess("$newTableName $sysId", 'Update values')) { $response = Invoke-ServiceNowRestMethod @params - if ( $PassThru.IsPresent ) { + if ( $PassThru ) { $response } } diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 4f98ee9..58cdbb6 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -27,7 +27,7 @@ Author = 'Sam Martin Rick Arroues Greg Brownstein' CompanyName = 'None' # Copyright statement for this module -Copyright = '(c) 2015-2021 Snow-Shell. All rights reserved.' +Copyright = '(c) 2015-2023 Snow-Shell. All rights reserved.' # Description of the functionality provided by this module Description = 'Automate against ServiceNow service and asset management. This module can be used standalone or with Azure Automation.' diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 5354f3e..13b25f0 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -22,8 +22,10 @@ $tableArgCompleterSb = { # assign the table arg completer to functions @( 'Get-ServiceNowRecord', - 'Get-ServiceNowAttachment' - 'Add-ServiceNowAttachment' + 'Get-ServiceNowAttachment', + 'Add-ServiceNowAttachment', + 'New-ServiceNowRecord', + 'Update-ServiceNowRecord' ) | ForEach-Object { Register-ArgumentCompleter -CommandName $_ -ParameterName 'Table' -ScriptBlock $tableArgCompleterSb } From 6a74992b86011144c4cd41b14b9b53c9ef6e2e69 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sat, 25 Feb 2023 11:10:38 -0500 Subject: [PATCH 325/348] check item props, not list (#235) --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 40063d6..016a090 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -317,10 +317,14 @@ function Get-ServiceNowRecord { $invokeParams.UriLeaf = '/attachment' } - $result = Invoke-ServiceNowRestMethod @invokeParams + [array]$result = Invoke-ServiceNowRestMethod @invokeParams + + if ( -not $result ) { + return + } # custom tables do not have a sys_class_name property, add it - if ( -not $Property -and $result.PSObject.Properties.name -notcontains 'sys_class_name' ) { + if ( -not $Property -and $result[0].PSObject.Properties.name -notcontains 'sys_class_name' ) { $result | Add-Member @{'sys_class_name' = $Table } } From b3abe811eda8ceff09a68d572c9bb6ff2730b94d Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Tue, 28 Feb 2023 15:16:05 +0000 Subject: [PATCH 326/348] Update ReadMe with casing correction of installation command (#236) --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 32729b1..88375c3 100644 --- a/Readme.md +++ b/Readme.md @@ -20,7 +20,7 @@ Requires authorization in your ServiceNow tenant. Due to the custom nature of S ## Usage -The ServiceNow module should be installed from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ServiceNow) with `install-module ServiceNow`. +The ServiceNow module should be installed from the [PowerShell Gallery](https://www.powershellgallery.com/packages/ServiceNow) with `Install-Module ServiceNow`. A [docker image](https://hub.docker.com/repository/docker/gdbarron/servicenow-module) is also available with [Microsoft's PowerShell base image](https://hub.docker.com/_/microsoft-powershell) and the ServiceNow module preinstalled. The following environment variables should be used: - SNOW_SERVER: the ServiceNow instance, eg. instance.service-now.com From 6d8ec7b6c26e099e3e0f2fc40f399a946932bb04 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 9 Mar 2023 19:39:44 -0500 Subject: [PATCH 327/348] Add change request model and template support (#238) --- Readme.md | 8 +- .../Private/Invoke-ServiceNowRestMethod.ps1 | 18 +- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 24 +-- .../Public/Get-ServiceNowRecordInterim.ps1 | 67 ------- .../Public/New-ServiceNowChangeRequest.ps1 | 166 +++++++++--------- ServiceNow/Public/New-ServiceNowRecord.ps1 | 17 +- ServiceNow/ServiceNow.format.ps1xml | 53 ++++++ ServiceNow/ServiceNow.psm1 | 8 - ServiceNow/config/main.json | 7 + 9 files changed, 183 insertions(+), 185 deletions(-) delete mode 100644 ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 diff --git a/Readme.md b/Readme.md index 88375c3..10d7af4 100644 --- a/Readme.md +++ b/Readme.md @@ -98,6 +98,8 @@ Contributions are gratefully received, so please feel free to submit a pull requ ## Authors -- [Sam Martin](https://github.com/Sam-Martin) -- [Rick Arroues](https://github.com/Rick-2CA) -- [Greg Brownstein](https://github.com/gdbarron) +- Current: [Greg Brownstein](https://github.com/gdbarron) + +- Previous + - [Sam Martin](https://github.com/Sam-Martin) + - [Rick Arroues](https://github.com/Rick-2CA) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 1652313..61f3fcc 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -121,20 +121,28 @@ function Invoke-ServiceNowRestMethod { if ($Property) { $Body.sysparm_fields = ($Property -join ',').ToLower() } + + if ( $Body ) { + $params.Body = $Body + } + + Write-Verbose ($params | ConvertTo-Json) } if ( $Values ) { $Body = $Values | ConvertTo-Json + $params.Body = $Body + Write-Verbose ($params | ConvertTo-Json) #Convert to UTF8 array to support special chars such as the danish "�","�","�" - $body = [System.Text.Encoding]::UTf8.GetBytes($Body) + $params.Body = [System.Text.Encoding]::UTf8.GetBytes($Body) } - if ( $Body ) { - $params.Body = $Body - } + # if ( $Body ) { + # $params.Body = $Body + # } - Write-Verbose ($params | ConvertTo-Json) + # Write-Verbose ($params | ConvertTo-Json) # hide invoke-webrequest progress $oldProgressPreference = $ProgressPreference diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 016a090..4e574d3 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -207,18 +207,6 @@ function Get-ServiceNowRecord { Write-Warning '-New is now deprecated and the new format is the default' } - $invokeParams = @{ - Filter = $Filter - Property = $Property - Sort = $Sort - DisplayValue = $DisplayValue - First = $PSCmdlet.PagingParameters.First - Skip = $PSCmdlet.PagingParameters.Skip - IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - if ( $Table ) { $thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } if ( -not $thisTable ) { @@ -236,6 +224,18 @@ function Get-ServiceNowRecord { process { + $invokeParams = @{ + Filter = $Filter + Property = $Property + Sort = $Sort + DisplayValue = $DisplayValue + First = $PSCmdlet.PagingParameters.First + Skip = $PSCmdlet.PagingParameters.Skip + IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + if ( $ID ) { if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { if ( -not $thisTable ) { diff --git a/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 b/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 deleted file mode 100644 index 8ff79e4..0000000 --- a/ServiceNow/Public/Get-ServiceNowRecordInterim.ps1 +++ /dev/null @@ -1,67 +0,0 @@ -function Get-ServiceNowRecordInterim { - [OutputType([System.Management.Automation.PSCustomObject])] - [CmdletBinding(SupportsPaging)] - Param( - # Machine name of the field to order by - [Parameter()] - [string] $OrderBy = 'opened_at', - - # Direction of ordering (Desc/Asc) - [Parameter()] - [ValidateSet('Desc', 'Asc')] - [string] $OrderDirection = 'Desc', - - # Fields to return - [Parameter()] - [Alias('Fields', 'Properties')] - [string[]] $Property, - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [Parameter()] - [hashtable] $MatchExact = @{}, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [Parameter()] - [hashtable] $MatchContains = @{}, - - # Whether or not to show human readable display values instead of machine values - [Parameter()] - [ValidateSet('true', 'false', 'all')] - [Alias('DisplayValues')] - [string] $DisplayValue = 'true', - - [Parameter()] - [hashtable] $Connection, - - [Parameter()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession - ) - - Write-Warning ('{0} will be deprecated in the near future. Please use Get-ServiceNowRecord instead.' -f $PSCmdlet.MyInvocation.InvocationName) - - $table = $ServiceNowTable | Where-Object { $PSCmdlet.MyInvocation.InvocationName.ToLower().Replace('get-servicenow', '') -eq $_.ClassName.Replace(' ', '').ToLower() } - - $newServiceNowQuerySplat = @{ - OrderBy = $OrderBy - MatchExact = $MatchExact - OrderDirection = $OrderDirection - MatchContains = $MatchContains - } - - $params = @{ - Table = $table.Name - Query = (New-ServiceNowQuery @newServiceNowQuerySplat) - DisplayValue = $DisplayValue - First = $PSCmdlet.PagingParameters.First - Skip = $PSCmdlet.PagingParameters.Skip - IncludeTotalCount = $PSCmdlet.PagingParameters.IncludeTotalCount - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - $result = Invoke-ServiceNowRestMethod @params - - If ( $result -and -not $Properties) { - $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $table.Type) } - } - $result -} \ No newline at end of file diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index c609921..b84fe21 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -4,98 +4,110 @@ function New-ServiceNowChangeRequest { Generates a new ServiceNow change request .DESCRIPTION - Generates a new ServiceNow change request using predefined or custom fields by invoking the ServiceNow API + Generates a new ServiceNow change request directly with values or via a change model or template. + + .PARAMETER ModelID + Name or sys_id of the change model to use + + .PARAMETER TemplateID + Name of sys_id of the standard change template to use .PARAMETER Caller - sys_id of the caller of the change request (user Get-ServiceNowUser to retrieve this) + Full name or sys_id of the caller .PARAMETER ShortDescription - Short description of the change request + Short description .PARAMETER Description - Long description of the change request + Long description .PARAMETER AssignmentGroup - sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) + Full name or sys_id of the assignment group .PARAMETER Comment - Comment to include in the ticket + Comment to include .PARAMETER Category - Category of the change request (e.g. 'Network') + Category name .PARAMETER Subcategory - Subcategory of the change request (e.g. 'Network') + Subcategory name .PARAMETER ConfigurationItem - sys_id of the configuration item of the change request + Full name or sys_id of the configuration item to be associated with the change - .PARAMETER CustomFields - Custom fields as hashtable + .PARAMETER CustomField + Custom field values which aren't one of the built in function properties .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance .PARAMETER PassThru - Returns the ticket values after creation + If provided, the new record will be returned + + .EXAMPLE + New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' - .LINK - https://github.com/Snow-Shell/servicenow-powershell + Create a basic change request .EXAMPLE - Generate a basic change request attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. + New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' -CustomField @{'urgency'='1'} - New-ServiceNowchange request -Caller UserName -ShortDescription 'New PS change request' -Description 'This change request was created from Powershell' -AssignmentGroup ServiceDesk -Comment 'Inline Comment' -Category Office -Subcategory Outlook -ConfigurationItem UserPC1 + Create a basic change request with custom fields .EXAMPLE - Generate an Change Request by 'splatting' all fields used in the 1st example plus some additional custom ServiceNow fields (These must exist in your ServiceNow instance), This example uses the caller's sys_id value for identification. - - $newServiceNowChangeRequestSplat = @{ - Caller = '55ccf91161924edc979d8e7e5627a47d' - ShortDescription = 'New PS Change Request' - Description = 'This change request was created from Powershell' - AssignmentGroup = 'ServiceDesk' - Comment = 'Inline Comment' - Category = 'Office' - Subcategory = 'Outlook' - ConfigurationItem = 'UserPC1' - CustomFields = @{ - u_custom1 = 'Custom Field Entry' - u_another_custom = 'Related Test' - } - } - New-ServiceNowChangeRequest @newServiceNowChangeRequestSplat + New-ServiceNowChangeRequest -TemplateID 'Change VLAN on a Cisco switchport - 1' + + Create a change request from a standard change template + + .EXAMPLE + New-ServiceNowChangeRequest -ModelID 'Normal' -ShortDescription 'make this change' -ConfigurationItem dbserver1 + + Create a change request from a change model + + .EXAMPLE + New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' -PassThru + + Create a change request and return the newly created record + #> - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'direct')] Param( - [parameter(Mandatory)] - [string]$Caller, + [parameter(Mandatory, ParameterSetName = 'model')] + [string] $ModelID, + + [parameter(Mandatory, ParameterSetName = 'template')] + [string] $TemplateID, + + [parameter()] + [string] $Caller, - [parameter(Mandatory)] - [string]$ShortDescription, + [parameter()] + [string] $ShortDescription, [parameter()] - [string]$Description, + [string] $Description, [parameter()] - [string]$AssignmentGroup, + [string] $AssignmentGroup, [parameter()] - [string]$Comment, + [string] $Comment, [parameter()] - [string]$Category, + [string] $Category, [parameter()] - [string]$Subcategory, + [string] $Subcategory, [parameter()] - [string]$ConfigurationItem, + [string] $ConfigurationItem, [parameter()] - [hashtable]$CustomFields, + [Alias('CustomFields')] + [hashtable] $CustomField, [Parameter()] [Hashtable] $Connection, @@ -110,58 +122,48 @@ function New-ServiceNowChangeRequest { begin {} process { - # Create a hash table of any defined parameters (not CustomFields) that have values - $DefinedChangeRequestParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') - $TableEntryValues = @{ } - ForEach ($Parameter in $DefinedChangeRequestParameters) { - If ($null -ne $PSBoundParameters.$Parameter) { - # Turn the defined parameter name into the ServiceNow attribute name - $KeyToAdd = Switch ($Parameter) { - AssignmentGroup { 'assignment_group'; break } - Caller { 'caller_id'; break } - Category { 'category'; break } - Comment { 'comments'; break } - ConfigurationItem { 'cmdb_ci'; break } - Description { 'description'; break } - ShortDescription { 'short_description'; break } - Subcategory { 'subcategory'; break } - } - $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) - } + + $values = @{} + Switch ($PSBoundParameters.Keys) { + AssignmentGroup { $values['assignment_group'] = $PSBoundParameters.AssignmentGroup } + Caller { $values['caller_id'] = $PSBoundParameters.Caller } + Category { $values['category'] = $PSBoundParameters.Category } + Comment { $values['comments'] = $PSBoundParameters.Comment } + ConfigurationItem { $values['cmdb_ci'] = $PSBoundParameters.ConfigurationItem } + Description { $values['description'] = $PSBoundParameters.Description } + ShortDescription { $values['short_description'] = $PSBoundParameters.ShortDescription } + Subcategory { $values['subcategory'] = $PSBoundParameters.Subcategory } + ModelID { $values['chg_model'] = $PSBoundParameters.ModelID } + TemplateID { $values['std_change_producer_version'] = $PSBoundParameters.TemplateID; $values['type'] = 'Standard' } } - # Add CustomFields hash pairs to the Table Entry Values hash table - If ($null -ne $PSBoundParameters.CustomFields) { - $DuplicateTableEntryValues = ForEach ($Key in $CustomFields.Keys) { - If (($TableEntryValues.ContainsKey($Key) -eq $False)) { - # Add the unique entry to the table entry values hash table - $TableEntryValues.Add($Key, $CustomFields[$Key]) - } - Else { - # Capture the duplicate key name - $Key - } + # add custom fields + $duplicateValues = ForEach ($Key in $CustomField.Keys) { + If ( $values.ContainsKey($Key) ) { + $Key + } + Else { + $values.Add($Key, $CustomField[$Key]) } } # Throw an error if duplicate fields were provided - If ($null -ne $DuplicateTableEntryValues) { - $DuplicateKeyList = $DuplicateTableEntryValues -join "," - Throw "Ticket fields may only be used once: $DuplicateKeyList" + If ( $duplicateValues ) { + Throw ('Fields may only be used once and the following were duplicated: {0}' -f $duplicateValues -join ",") } # Table Entry Splat $params = @{ - Method = 'Post' Table = 'change_request' - Values = $TableEntryValues + Values = $values Connection = $Connection ServiceNowSession = $ServiceNowSession + PassThru = $true } - If ( $PSCmdlet.ShouldProcess($ShortDescription, 'Create new change request') ) { - $response = Invoke-ServiceNowRestMethod @params - If ($PassThru.IsPresent) { + If ( $PSCmdlet.ShouldProcess('', 'Create new change request') ) { + $response = New-ServiceNowRecord @params + If ( $PassThru ) { $response.PSObject.TypeNames.Insert(0, "ServiceNow.ChangeRequest") $response } diff --git a/ServiceNow/Public/New-ServiceNowRecord.ps1 b/ServiceNow/Public/New-ServiceNowRecord.ps1 index fd946fb..bf3344d 100644 --- a/ServiceNow/Public/New-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/New-ServiceNowRecord.ps1 @@ -12,8 +12,8 @@ Hashtable with all the key/value pairs for the new record .PARAMETER PassThru - If provided, the new record will be returned - + If provided, the new record will be returned + .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance @@ -22,6 +22,7 @@ .EXAMPLE New-ServiceNowRecord -Table incident -Values @{'Caller'='me';'short_description'='my issue'} + Create a new record in the incident table .INPUTS @@ -36,11 +37,9 @@ function New-ServiceNowRecord { Param ( - # Name of the table we're inserting into (e.g. incidents) [parameter(Mandatory)] [string] $Table, - # Hashtable of values to use as the record's properties [parameter(Mandatory)] [hashtable] $Values, @@ -55,12 +54,14 @@ function New-ServiceNowRecord { ) $invokeParams = $PSBoundParameters - $invokeParams.Remove('PassThru') | Out-Null + $null = $invokeParams.Remove('PassThru') + + If ( $PSCmdlet.ShouldProcess($Table, 'Create new record') ) { - If ( $PSCmdlet.ShouldProcess($Table, 'Create new entry') ) { $response = Invoke-ServiceNowRestMethod @invokeParams -Method 'Post' - If ($PassThru.IsPresent) { - $type = $script:ServiceNowTable | Where-Object {$_.Name -eq $Table -or $_.ClassName -eq $Table} | Select-Object -ExpandProperty Type + + If ( $PassThru ) { + $type = $script:ServiceNowTable | Where-Object { $_.Name -eq $Table -or $_.ClassName -eq $Table } | Select-Object -ExpandProperty Type if ($type) { $response | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } } diff --git a/ServiceNow/ServiceNow.format.ps1xml b/ServiceNow/ServiceNow.format.ps1xml index 8990bc0..bc0841a 100644 --- a/ServiceNow/ServiceNow.format.ps1xml +++ b/ServiceNow/ServiceNow.format.ps1xml @@ -395,6 +395,59 @@ + + ServiceNow.Task + + ServiceNow.Task + + + + + + 12 + + + + 10 + + + + 20 + + + + 12 + + + + 32 + + + + + + + number + + + state + + + sys_class_name + + + + $_.parent.display_value + + + + sys_id + + + + + + ServiceNow.ChangeTask diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 13b25f0..070c602 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -49,14 +49,6 @@ $Script:ServiceNowSession = @{} Export-ModuleMember -Variable ServiceNowSession $aliases = @{ - 'Get-ServiceNowRequestItem' = 'Get-ServiceNowRequestedItem' - 'Get-ServiceNowIncident' = 'Get-ServiceNowRecordInterim' - 'Get-ServiceNowChangeRequest' = 'Get-ServiceNowRecordInterim' - 'Get-ServiceNowConfigurationItem' = 'Get-ServiceNowRecordInterim' - 'Get-ServiceNowRequest' = 'Get-ServiceNowRecordInterim' - 'Get-ServiceNowRequestedItem' = 'Get-ServiceNowRecordInterim' - 'Get-ServiceNowUser' = 'Get-ServiceNowRecordInterim' - 'Get-ServiceNowUserGroup' = 'Get-ServiceNowRecordInterim' 'Update-ServiceNowRequestItem' = 'Update-ServiceNowRequestedItem' 'Remove-ServiceNowTableEntry' = 'Remove-ServiceNowRecord' 'New-ServiceNowTableEntry' = 'New-ServiceNowRecord' diff --git a/ServiceNow/config/main.json b/ServiceNow/config/main.json index 9b27e94..a07abd1 100644 --- a/ServiceNow/config/main.json +++ b/ServiceNow/config/main.json @@ -55,6 +55,13 @@ "NumberPrefix": "sctask", "DescriptionField": "short_description" }, + { + "Name": "task", + "ClassName": "Task", + "Type": "ServiceNow.Task", + "NumberPrefix": "task", + "DescriptionField": "short_description" + }, { "Name": "change_task", "ClassName": "Change Task", From 97caff7a1ebdbd7ec347a792f78939a90b25bf59 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 16 Mar 2023 19:10:22 -0400 Subject: [PATCH 328/348] Major update (#240) --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 4 +- ServiceNow/Private/Invoke-TableIdLookup.ps1 | 108 +++++++ .../Public/Add-ServiceNowAttachment.ps1 | 93 ++---- .../Public/Export-ServiceNowAttachment.ps1 | 50 +-- ServiceNow/Public/Export-ServiceNowRecord.ps1 | 68 ++-- .../Public/Get-ServiceNowAttachment.ps1 | 86 ++--- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 187 ++++++----- .../Public/New-ServiceNowChangeRequest.ps1 | 125 ++++---- .../New-ServiceNowConfigurationItem.ps1 | 6 +- ServiceNow/Public/New-ServiceNowIncident.ps1 | 115 ++++--- ServiceNow/Public/New-ServiceNowQuery.ps1 | 302 ++++++++---------- ServiceNow/Public/New-ServiceNowRecord.ps1 | 44 ++- ServiceNow/Public/Remove-ServiceNowRecord.ps1 | 66 ++-- .../Public/Update-ServiceNowChangeRequest.ps1 | 50 --- .../Public/Update-ServiceNowIncident.ps1 | 47 --- ServiceNow/Public/Update-ServiceNowRecord.ps1 | 131 ++++---- .../Public/Update-ServiceNowRequestedItem.ps1 | 69 ---- ServiceNow/ServiceNow.psd1 | 22 +- ServiceNow/ServiceNow.psm1 | 14 +- 19 files changed, 743 insertions(+), 844 deletions(-) create mode 100644 ServiceNow/Private/Invoke-TableIdLookup.ps1 delete mode 100644 ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 delete mode 100644 ServiceNow/Public/Update-ServiceNowIncident.ps1 delete mode 100644 ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 61f3fcc..1f8655e 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -43,10 +43,10 @@ function Invoke-ServiceNowRestMethod { [hashtable] $Values, [parameter()] - [System.Collections.ArrayList] $Filter, + [object[]] $Filter, [parameter()] - [System.Collections.ArrayList] $Sort = @('opened_at', 'desc'), + [object[]] $Sort = @('opened_at', 'desc'), # sysparm_query param in the format of a ServiceNow encoded query string (see http://wiki.servicenow.com/index.php?title=Encoded_Query_Strings) [Parameter()] diff --git a/ServiceNow/Private/Invoke-TableIdLookup.ps1 b/ServiceNow/Private/Invoke-TableIdLookup.ps1 new file mode 100644 index 0000000..acd2e2b --- /dev/null +++ b/ServiceNow/Private/Invoke-TableIdLookup.ps1 @@ -0,0 +1,108 @@ +<# +.SYNOPSIS + Lookup table and id info +.DESCRIPTION + Lookup table and id info from module config. + Get sys_id if needed. +#> +function Invoke-TableIdLookup { + + [OutputType([Array])] + [CmdletBinding()] + + Param ( + [Parameter(ParameterSetName = 'Table', Mandatory)] + [Parameter(ParameterSetName = 'TableID', Mandatory)] + [Parameter(ParameterSetName = 'TableIdSysId', Mandatory)] + [AllowEmptyString()] + [AllowNull()] + [Alias('T')] + [string] $Table, + + [Parameter(ParameterSetName = 'ID', Mandatory)] + [Parameter(ParameterSetName = 'TableID', Mandatory)] + [Parameter(ParameterSetName = 'IdSysId', Mandatory)] + [Parameter(ParameterSetName = 'TableIdSysId', Mandatory)] + [AllowEmptyString()] + [AllowNull()] + [Alias('I')] + [string] $ID, + + [Parameter(ParameterSetName = 'IdSysId', Mandatory)] + [Parameter(ParameterSetName = 'TableIdSysId', Mandatory)] + [Alias('AS')] + [switch] $AsSysId, + + [Parameter(ParameterSetName = 'IdSysId')] + [Parameter(ParameterSetName = 'TableIdSysId')] + [Alias('C')] + [hashtable] $Connection, + + [Parameter(ParameterSetName = 'IdSysId')] + [Parameter(ParameterSetName = 'TableIdSysId')] + [Alias('S')] + [hashtable] $ServiceNowSession + + ) + + $thisTable = $thisID = $null + + if ( $Table ) { + $thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } + if ( -not $thisTable ) { + # we aren't aware of this table, create default config + $thisTable = @{ + Name = $Table + ClassName = $null + Type = $null + NumberPrefix = $null + DescriptionField = $null + } + } + } + + if ( $ID ) { + if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { + if ( -not $thisTable ) { + throw 'Providing sys_id for -ID requires a value for -Table. Alternatively, provide an ID with a prefix, eg. INC1234567, and the table will be automatically determined.' + } + + $thisID = $ID + } + else { + if ( -not $thisTable ) { + # get table name from prefix if only Id was provided + $idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() + + $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } + if ( -not $thisTable ) { + throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) + } + } + + if ( $AsSysId ) { + $getParams = @{ + Table = $thisTable.Name + Filter = @('number', '-eq', $ID) + Property = 'sys_class_name', 'sys_id', 'number' + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + + $thisRecord = Invoke-ServiceNowRestMethod @getParams + + if ( -not $thisRecord ) { + throw ('Table: {0}, ID: {1} not found' -f $thisTable.Name, $ID) + } + else { + $thisID = $thisRecord.sys_id + } + } + else { + $thisID = $ID + } + } + } + + $thisTable, $thisID +} diff --git a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 index 4c553d4..6171880 100644 --- a/ServiceNow/Public/Add-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Add-ServiceNowAttachment.ps1 @@ -42,6 +42,11 @@ Function Add-ServiceNowAttachment { Upload one or more files by record sys_id + .EXAMPLE + Get-ServiceNowRecord inc0000010 | Add-ServiceNowAttachment -File '.\File01.txt' + + Use Get-ServiceNowRecord for record details, one or more, to add an attachment to + .EXAMPLE New-ServiceNowIncident @params -PassThru | Add-ServiceNowAttachment -File file01.txt @@ -69,18 +74,14 @@ Function Add-ServiceNowAttachment { [CmdletBinding(SupportsShouldProcess)] Param( - [Parameter(ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'Table', Mandatory)] + [Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, - [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] - [ValidateScript( { - if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { - $true - } else { - throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' - } - })] + # validation not needed as Invoke-TableIdLookup will handle it with -AsSysId + [Parameter(ParameterSetName = 'Id', Mandatory, ValueFromPipeline, Position = 0)] + [Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id', 'SysId', 'number')] [string] $ID, @@ -88,7 +89,8 @@ Function Add-ServiceNowAttachment { [ValidateScript( { if ( Test-Path $_ ) { $true - } else { + } + else { throw 'One or more files do not exist' } })] @@ -111,62 +113,24 @@ Function Add-ServiceNowAttachment { begin { $auth = Get-ServiceNowAuth -C $Connection -S $ServiceNowSession - $invokeRestMethodSplat = $auth - $invokeRestMethodSplat.UseBasicParsing = $true - $invokeRestMethodSplat.Method = 'POST' + $params = $auth + $params.UseBasicParsing = $true + $params.Method = 'POST' } process { - if ( $Table ) { - $thisTableName = $ServiceNowTable.Where{ $_.ClassName -eq $Table } | Select-Object -ExpandProperty Name - if ( -not $thisTableName ) { - $thisTableName = $Table - } - } - - if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { - if ( -not $thisTableName ) { - Write-Error 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an -Id with a prefix, eg. INC1234567, and the table will be automatically determined.' - Continue - } - - $thisSysId = $ID - - } else { - if ( -not $thisTableName ) { - $thisTable = $ServiceNowTable.Where{ $_.NumberPrefix -and $ID.ToLower().StartsWith($_.NumberPrefix) } - if ( $thisTable ) { - $thisTableName = $thisTable.Name - } else { - Write-Error ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) - Continue - } - } - - $getParams = @{ - Table = $thisTableName - Id = $ID - Property = 'sys_id' - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - - $tableRecord = Get-ServiceNowRecord @getParams - - if ( -not $tableRecord ) { - Write-Error "Record not found for Id '$ID'" - continue - } - - $thisSysId = $tableRecord.sys_id - } - + $thisTable, $thisID = Invoke-TableIdLookup -T $Table -I $ID -AsSysId -C $Connection -S $ServiceNowSession foreach ($thisFile in $File) { $thisFileObject = Get-ChildItem $thisFile + if ( $thisFileObject.Size -eq 0 ) { + Write-Warning ('{0} is a 0 byte file and will not be uploaded' -f $thisFileObject.FullName) + Continue + } + If ( -not $PSBoundParameters.ContainsKey('ContentType') ) { # Thanks to https://github.com/samuelneff/MimeTypeMap/blob/master/MimeTypeMap.cs from which # MimeTypeMap.json was adapted @@ -182,22 +146,23 @@ Function Add-ServiceNowAttachment { } # POST: https://instance.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=d71f7935c0a8016700802b64c67c11c6&file_name=Issue_screenshot - $invokeRestMethodSplat.Uri = '{0}/attachment/file?table_name={1}&table_sys_id={2}&file_name={3}' -f $auth.Uri, $thisTableName, $thisSysId, $thisFileObject.Name - $invokeRestMethodSplat.ContentType = $ContentType - $invokeRestMethodSplat.InFile = $thisFileObject.FullName + $params.Uri = '{0}/attachment/file?table_name={1}&table_sys_id={2}&file_name={3}' -f $auth.Uri, $thisTable.Name, $thisID, $thisFileObject.Name + $params.ContentType = $ContentType + $params.InFile = $thisFileObject.FullName - If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $thisTableName, $thisSysId), ('Add attachment {0}' -f $thisFileObject.FullName))) { + If ($PSCmdlet.ShouldProcess(('{0} {1}' -f $thisTable.Name, $ID), ('Add attachment {0}' -f $thisFileObject.FullName))) { - Write-Verbose ($invokeRestMethodSplat | ConvertTo-Json) + Write-Verbose ($params | ConvertTo-Json) - $response = Invoke-WebRequest @invokeRestMethodSplat + $response = Invoke-WebRequest @params if ( $response.Content ) { if ( $PassThru ) { $content = $response.content | ConvertFrom-Json $content.result } - } else { + } + else { # invoke-webrequest didn't throw an error, but we didn't get content back either throw ('"{0} : {1}' -f $response.StatusCode, $response | Out-String ) } diff --git a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 index 8eb4656..6786a1b 100644 --- a/ServiceNow/Public/Export-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Export-ServiceNowAttachment.ps1 @@ -1,12 +1,13 @@ <# .SYNOPSIS -Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. +Export an attachment .DESCRIPTION -Save a ServiceNow attachment identified by its sys_id property and saved as the filename specified. +Export an attachment identified by its attachment table sys_id. +The contents will be saved to a file by default, but can also be outputted directly. -.PARAMETER SysID -The ServiceNow sys_id of the file +.PARAMETER ID +The attachment table sys_id of the file .PARAMETER FileName File name the file is saved as. Do not include the path. @@ -24,27 +25,30 @@ Adds the SysID to the file name. Intended for use when a ticket has multiple fi Instead of writing to a file, return the attachment contents .EXAMPLE -Export-ServiceNowAttachment -SysID $SysID -FileName 'mynewfile.txt' +Export-ServiceNowAttachment -ID $SysID -FileName 'mynewfile.txt' Save the attachment with the specified sys_id with a name of 'mynewfile.txt' .EXAMPLE -Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment +Get-ServiceNowAttachment -ID INC1234567 | Export-ServiceNowAttachment -Save all attachments from the ticket. Filenames will be assigned from the attachment name. +Save all attachments from the ticket. +Filenames will be assigned from the attachment name. .EXAMPLE -Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -AppendNameWithSysID +Get-ServiceNowAttachment -ID INC1234567 | Export-ServiceNowAttachment -AppendNameWithSysID -Save all attachments from the ticket. Filenames will be assigned from the attachment name and appended with the sys_id. +Save all attachments from the ticket. +Filenames will be assigned from the attachment name and appended with the sys_id. .EXAMPLE -Get-ServiceNowAttachment -Id INC1234567 | Export-ServiceNowAttachment -Destination $path -AllowOverwrite +Get-ServiceNowAttachment -ID INC1234567 | Export-ServiceNowAttachment -Destination $path -AllowOverwrite Save all attachments from the ticket to the destination allowing for overwriting the destination file. .EXAMPLE -Export-ServiceNowAttachment -SysId $SysId -AsValue +Export-ServiceNowAttachment -ID $ID -AsValue + Return the contents of the attachment instead of writing to a file #> @@ -55,8 +59,16 @@ Function Export-ServiceNowAttachment { Param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $SysId, + [ValidateScript( { + if ( $_ -match '^[a-zA-Z0-9]{32}$' ) { + $true + } + else { + throw '-ID must be a sys_id 32 character alphanumeric' + } + })] + [Alias('sys_id', 'SysID')] + [string] $ID, [Parameter(ParameterSetName = 'ToFile', ValueFromPipelineByPropertyName)] [Alias('file_name')] @@ -95,25 +107,25 @@ Function Export-ServiceNowAttachment { $params = $authParams.Clone() - $params.Uri += '/attachment/' + $SysId + '/file' + $params.Uri += '/attachment/' + $ID + '/file' + # if not to file, attachment contents to output if ( $PSCmdlet.ParameterSetName -eq 'ToFile' ) { $thisFileName = $FileName - If ( $AppendNameWithSysId.IsPresent ) { - $thisFileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($thisFileName), $SysId, [io.path]::GetExtension($thisFileName) + If ( $AppendNameWithSysId ) { + $thisFileName = "{0}_{1}{2}" -f [io.path]::GetFileNameWithoutExtension($thisFileName), $ID, [io.path]::GetExtension($thisFileName) } $outFile = Join-Path $Destination $thisFileName - If ((Test-Path $outFile) -and -not $AllowOverwrite.IsPresent) { + If ((Test-Path $outFile) -and -not $AllowOverwrite ) { throw ('The file ''{0}'' already exists. Please choose a different name, use the -AppendNameWithSysID switch parameter, or use the -AllowOverwrite switch parameter to overwrite the file.' -f $OutFile) } $params.OutFile = $outFile } - If ($PSCmdlet.ShouldProcess($outFile, "Save attachment")) { + If ($PSCmdlet.ShouldProcess($ID, "Export attachment")) { Invoke-RestMethod @params } } - end {} } diff --git a/ServiceNow/Public/Export-ServiceNowRecord.ps1 b/ServiceNow/Public/Export-ServiceNowRecord.ps1 index 8999fac..514440d 100644 --- a/ServiceNow/Public/Export-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Export-ServiceNowRecord.ps1 @@ -67,6 +67,12 @@ .LINK https://docs.servicenow.com/bundle/sandiego-platform-administration/page/administer/exporting-data/task/t_ExportDirectlyFromTheURL.html#t_ExportDirectlyFromTheURL + +.INPUTS + Table, ID + +.OUTPUTS + None #> function Export-ServiceNowRecord { @@ -74,38 +80,41 @@ function Export-ServiceNowRecord { Param ( [Parameter(ParameterSetName = 'Table', Mandatory)] + [Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, [Parameter(ParameterSetName = 'Id', Mandatory, Position = 0)] - [Parameter(ParameterSetName = 'Table')] + [Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipelineByPropertyName)] [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true - } else { - throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' + } + else { + throw 'Id must either be a SysId 32 character alphanumeric or Number with prefix and id.' } })] - [Alias('sys_id', 'number')] + [Alias('sys_id', 'SysId', 'number')] [string] $ID, [Parameter()] [Alias('Fields', 'Properties')] [string[]] $Property, - [Parameter()] - [System.Collections.ArrayList] $Filter, + [Parameter(ParameterSetName = 'Table')] + [object[]] $Filter = @(), - [parameter()] + [Parameter(ParameterSetName = 'Table')] [ValidateNotNullOrEmpty()] - [System.Collections.ArrayList] $Sort, + [object[]] $Sort, [Parameter(Mandatory)] [ValidateScript({ $allowedExts = '.csv', '.xml', '.pdf', '.xls', '.xlsx' if ([System.IO.Path]::GetExtension($_).ToLower() -in $allowedExts ) { $true - } else { + } + else { throw ('File extension must be one of {0}' -f ($allowedExts -join ', ')) } })] @@ -119,34 +128,31 @@ function Export-ServiceNowRecord { $newFilter = $Filter - if ( $Table ) { - $thisTable = $Table + if ( $PSBoundParameters.ContainsKey('Filter') ) { + # # we always want the filter to be arrays separated by joins + if ( $Filter[0].GetType().Name -ne 'Object[]' ) { + # + $newFilter = , $Filter + } } - if ( $ID ) { - if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { - if ( -not $thisTable ) { - throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' - } + $thisTable, $thisID = Invoke-TableIdLookup -T $Table -I $ID - $newFilter = @('sys_id', '-eq', $ID) - } else { - if ( -not $thisTable ) { - # get table name from prefix if only Id was provided - $idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() - Write-Debug "Id prefix is $idPrefix" - $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } | Select-Object -ExpandProperty Name - if ( -not $thisTable ) { - throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) - } - } - $newFilter = @('number', '-eq', $ID) + if ( $thisID ) { + + if ( $thisID -match '^[a-zA-Z0-9]{32}$' ) { + $newFilter = , @('sys_id', '-eq', $thisID) + } + else { + $newFilter = , @('number', '-eq', $thisID) } } $params = Get-ServiceNowAuth -S $ServiceNowSession - $params.Body = @{ - 'sysparm_query' = (New-ServiceNowQuery -Filter $newFilter -Sort $Sort) + $params.Body = @{} + + if ( $newFilter ) { + $params.Body.sysparm_query = (New-ServiceNowQuery -Filter $newFilter -Sort $Sort) } if ($Property) { @@ -161,7 +167,7 @@ function Export-ServiceNowRecord { # only exception to 'extension is the format' rule if ( $format -eq 'XLS' ) { $format = 'EXCEL' } - $params.Uri = 'https://{0}/{1}_list.do?{2}' -f $ServiceNowSession.Domain, $thisTable, $format + $params.Uri = 'https://{0}/{1}_list.do?{2}' -f $ServiceNowSession.Domain, $thisTable.Name, $format Write-Verbose ($params | ConvertTo-Json) Invoke-RestMethod @params diff --git a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 index 94033f0..44747dd 100644 --- a/ServiceNow/Public/Get-ServiceNowAttachment.ps1 +++ b/ServiceNow/Public/Get-ServiceNowAttachment.ps1 @@ -54,6 +54,11 @@ Function Get-ServiceNowAttachment { Get attachment details where size is greater than 1M. + .EXAMPLE + Get-ServiceNowRecord -table incident -first 5 | Get-ServiceNowAttachment + + Get attachment details from multiple records + .INPUTS Table, ID @@ -65,18 +70,14 @@ Function Get-ServiceNowAttachment { [CmdletBinding(SupportsPaging)] Param( - [Parameter(ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'Table', Mandatory)] + [Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, - [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] - [ValidateScript( { - if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { - $true - } else { - throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' - } - })] + # validation not needed as Invoke-TableIdLookup will handle it with -AsSysId + [Parameter(ParameterSetName = 'Id', Mandatory, ValueFromPipeline, Position = 0)] + [Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id', 'SysId', 'number')] [string] $ID, @@ -84,11 +85,11 @@ Function Get-ServiceNowAttachment { [string] $FileName, [Parameter()] - [System.Collections.ArrayList] $Filter, + [object[]] $Filter, [parameter()] [ValidateNotNullOrEmpty()] - [System.Collections.ArrayList] $Sort, + [object[]] $Sort, [Parameter()] [Hashtable] $Connection, @@ -106,71 +107,20 @@ Function Get-ServiceNowAttachment { Connection = $Connection ServiceNowSession = $ServiceNowSession } - } process { - if ( $Table ) { - $thisTableName = $ServiceNowTable.Where{ $_.ClassName -eq $Table } | Select-Object -ExpandProperty Name - if ( -not $thisTableName ) { - $thisTableName = $Table - } - } - - if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { - if ( -not $thisTableName ) { - Write-Error 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an -Id with a prefix, eg. INC1234567, and the table will be automatically determined.' - Continue - } - - $thisSysId = $ID - - } else { - if ( -not $thisTableName ) { - $thisTable = $ServiceNowTable.Where{ $_.NumberPrefix -and $ID.ToLower().StartsWith($_.NumberPrefix) } - if ( $thisTable ) { - $thisTableName = $thisTable.Name - } else { - Write-Error ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) - Continue - } - } - - $getParams = @{ - Table = $thisTableName - Id = $ID - Property = 'sys_id' - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - - $tableRecord = Get-ServiceNowRecord @getParams - - if ( -not $tableRecord ) { - Write-Error "Record not found for ID '$ID'" - continue - } - - $thisSysId = $tableRecord.sys_id - } + $thisTable, $thisID = Invoke-TableIdLookup -T $Table -I $ID -AsSysId -C $Connection -S $ServiceNowSession - $params.Filter = @(@('table_name', '-eq', $thisTableName), 'and', @('table_sys_id', '-eq', $thisSysId)) + $params.Filter = @('table_name', '-eq', $thisTable.Name), 'and', @('table_sys_id', '-eq', $thisID) - if ( $FileName ) { - if ( $params.Filter ) { - $params.Filter += 'and', @('file_name', '-like', $FileName) - } else { - $params.Filter = @('file_name', '-like', $FileName) - } + if ( $PSBoundParameters.ContainsKey('FileName') ) { + $params.Filter += 'and', @('file_name', '-like', $FileName) } - if ( $Filter ) { - if ( $params.Filter ) { - $params.Filter += 'and', $Filter - } else { - $params.Filter = $Filter - } + if ( $PSBoundParameters.ContainsKey('Filter') ) { + $params.Filter += 'and', $Filter } $response = Invoke-ServiceNowRestMethod @params diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 4e574d3..5441853 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -48,7 +48,7 @@ Some records may have associated custom variables, some may not. For instance, an RITM may have custom variables, but the associated tasks may not. A property named 'CustomVariable' will be added to the return object. - When used with -New, you can now get the value with $return.CustomVariable.CustomVarName.Value. + You can get the value with $return.CustomVariable.CustomVarName.Value. .PARAMETER AsValue Return the underlying value instead of pscustomobject. @@ -63,22 +63,32 @@ .EXAMPLE Get-ServiceNowRecord RITM0010001 + Get a specific record by number .EXAMPLE Get-ServiceNowRecord -Id RITM0010001 -Property 'short_description','sys_id' + Get specific properties for a record .EXAMPLE Get-ServiceNowRecord -Table 'Catalog Task' -ParentId 'RITM0010001' - Get tasks for the parent requested item + + Get catalog tasks for the parent requested item + +.EXAMPLE + Get-ServiceNowRecord -ParentId 'RITM0010001' + + Get all tasks of all types for the parent requested item .EXAMPLE Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Description 'powershell' - Get incident records where state equals New or short description contains the word powershell + + Get incident records where state equals New and short description contains the word powershell .EXAMPLE Get-ServiceNowRecord -Table incident -Filter @('assigned_to.name', '-like', 'greg') + Get incident records where the assigned to user's name contains greg .EXAMPLE @@ -88,35 +98,49 @@ '-group', @('state', '-eq', '2') PS > Get-ServiceNowRecord -Table incident -Filter $filter + Get incident records where state is New and short description contains the word powershell or state is In Progress. The first 2 filters are combined and then or'd against the last. .EXAMPLE Get-ServiceNowRecord -Table 'Incident' -Filter @('opened_at', '-between', (Get-Date).AddMonths(-24), (get-date).AddMonths(-12)) -IncludeTotalCount + Get all incident records that were opened between 1 and 2 years ago .EXAMPLE Get-ServiceNowRecord -Table incident -Filter @('state', '-eq', '1') -Sort @('opened_at', 'desc'), @('state') + Get incident records where state equals New and first sort by the field opened_at descending and then sort by the field state ascending ] .EXAMPLE - Get-ServiceNowRecord -Table 'change request' -Filter @('opened_at', '-ge', 'javascript:gs.daysAgoEnd(30)') + Get-ServiceNowRecord -Table 'change request' -Filter @('opened_at', '-ge', (Get-Date).AddDays(-30)) + Get change requests opened in the last 30 days. Use class name as opposed to table name. .EXAMPLE Get-ServiceNowRecord -Table 'change request' -First 100 -IncludeTotalCount + Get all change requests, paging 100 at a time. .EXAMPLE Get-ServiceNowRecord -Table 'change request' -IncludeCustomVariable -First 5 + Get the first 5 change requests and retrieve custom variable info +.EXAMPLE + Get-ServiceNowRecord -Table 'user' -Filter @{'name', '-like', 'Greg'} + + Find results from tables where there is no number field. + In this case, get a list of users whose name has 'Greg' in it. + .EXAMPLE Get-ServiceNowRecord -Table 'cmdb_ci' -Property sys_id -First 1 -AsValue + Get the underlying value for a property instead of a pscustomobject where the value needs to be extracted .EXAMPLE gsnr RITM0010001 + Get a specific record by number using the function alias .INPUTS @@ -139,46 +163,51 @@ function Get-ServiceNowRecord { Param ( [Parameter(ParameterSetName = 'Table', Mandatory)] + [Parameter(ParameterSetName = 'TableId', Mandatory)] + [Parameter(ParameterSetName = 'TableParentId')] [Alias('sys_class_name')] [string] $Table, [Parameter(ParameterSetName = 'Id', Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)] - [Parameter(ParameterSetName = 'Table', ValueFromPipeline, ValueFromPipelineByPropertyName)] + [Parameter(ParameterSetName = 'TableId', Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true } else { - throw 'Id must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' + throw 'Id must either be a SysId 32 character alphanumeric or Number with prefix and id.' } })] [Alias('sys_id', 'number')] [string] $ID, - [Parameter()] + [Parameter(ParameterSetName = 'TableParentId', Mandatory)] [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true } else { - throw 'ParentId must be either a 32 character alphanumeric, ServiceNow sysid, or prefix/id, ServiceNow number.' + throw 'ParentId must either be a SysId 32 character alphanumeric or Number with prefix and id.' } })] [string] $ParentID, - [Parameter()] + [Parameter(ParameterSetName = 'Table')] + [Parameter(ParameterSetName = 'TableParentId')] [string] $Description, [Parameter()] [Alias('Fields', 'Properties')] [string[]] $Property, - [Parameter()] - [System.Collections.ArrayList] $Filter, + [Parameter(ParameterSetName = 'Table')] + [Parameter(ParameterSetName = 'TableParentId')] + [object[]] $Filter = @(), - [parameter()] + [Parameter(ParameterSetName = 'Table')] + [Parameter(ParameterSetName = 'TableParentId')] [ValidateNotNullOrEmpty()] - [System.Collections.ArrayList] $Sort, + [object[]] $Sort, [Parameter()] [ValidateSet('true', 'false', 'all')] @@ -188,9 +217,6 @@ function Get-ServiceNowRecord { [Parameter()] [switch] $IncludeCustomVariable, - [Parameter()] - [switch] $New, - [Parameter()] [switch] $AsValue, @@ -203,28 +229,11 @@ function Get-ServiceNowRecord { begin { - if ( $New ) { - Write-Warning '-New is now deprecated and the new format is the default' - } - - if ( $Table ) { - $thisTable = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $Table.ToLower() -or $_.ClassName.ToLower() -eq $Table.ToLower() } - if ( -not $thisTable ) { - # we aren't aware of this table, create default config - $thisTable = @{ - Name = $Table - ClassName = $null - Type = $null - NumberPrefix = $null - DescriptionField = $null - } - } - } } process { - $invokeParams = @{ + $thisParams = @{ Filter = $Filter Property = $Property Sort = $Sort @@ -236,52 +245,51 @@ function Get-ServiceNowRecord { ServiceNowSession = $ServiceNowSession } - if ( $ID ) { - if ( $ID -match '^[a-zA-Z0-9]{32}$' ) { - if ( -not $thisTable ) { - throw 'Providing sys_id for -Id requires a value for -Table. Alternatively, provide an Id with a prefix, eg. INC1234567, and the table will be automatically determined.' - } - - $idFilter = @('sys_id', '-eq', $ID) + if ( $PSBoundParameters.ContainsKey('Filter') ) { + # # we always want the filter to be arrays separated by joins + if ( $Filter[0].GetType().Name -ne 'Object[]' ) { + # + $thisParams.Filter = , $Filter } - else { - if ( -not $thisTable ) { - # get table name from prefix if only Id was provided - $idPrefix = ($ID | Select-String -Pattern '^([a-zA-Z]+)([0-9]+$)').Matches.Groups[1].Value.ToLower() - Write-Debug "Id prefix is $idPrefix" - $thisTable = $script:ServiceNowTable | Where-Object { $_.NumberPrefix -and $idPrefix -eq $_.NumberPrefix } - if ( -not $thisTable ) { - throw ('The prefix for Id ''{0}'' was not found and the appropriate table cannot be determined. Known prefixes are {1}. Please provide a value for -Table.' -f $ID, ($ServiceNowTable.NumberPrefix.Where( { $_ }) -join ', ')) - } - } - $idFilter = @('number', '-eq', $ID) + } + + $addedSysIdProp = $false + # we need the sys_id value in order to get custom var data + # add it in if specific properties were requested and not part of the list + if ( $IncludeCustomVariable ) { + if ( $Property -and 'sys_id' -notin $Property ) { + $thisParams.Property += 'sys_id' + $addedSysIdProp = $true } + } + + $thisTable, $thisID = Invoke-TableIdLookup -T $Table -I $ID + + if ( $thisID ) { - if ( $invokeParams.Filter ) { - $invokeParams.Filter = $invokeParams.Filter, 'and', $idFilter + if ( $thisID -match '^[a-zA-Z0-9]{32}$' ) { + $thisParams.Filter += , @('sys_id', '-eq', $thisID) } else { - $invokeParams.Filter = $idFilter + $thisParams.Filter += , @('number', '-eq', $thisID) } - } - # we have the table, update the params - $invokeParams.Table = $thisTable.Name - if ( $ParentID ) { + + if ( $thisParams.Filter ) { + $thisParams.Filter += , 'and' + } + if ( $ParentID -match '^[a-zA-Z0-9]{32}$' ) { - $parentIdFilter = @('parent.sys_id', '-eq', $ParentID) + $thisParams.Filter += , @('parent.sys_id', '-eq', $ParentID) } else { - $parentIdFilter = @('parent.number', '-eq', $ParentID) + $thisParams.Filter += , @('parent.number', '-eq', $ParentID) } - if ( $invokeParams.Filter ) { - $invokeParams.Filter = $invokeParams.Filter, 'and', $parentIdFilter - } - else { - $invokeParams.Filter = $parentIdFilter + if ( -not $PSBoundParameters.ContainsKey('Table') ) { + $thisTable, $null = Invoke-TableIdLookup -T 'Task' -I $null } } @@ -292,32 +300,24 @@ function Get-ServiceNowRecord { $thisTable.DescriptionField = 'short_description' } - if ( $invokeParams.Filter ) { - $invokeParams.Filter = $invokeParams.Filter, 'and', @($thisTable.DescriptionField, '-like', $Description) - } - else { - $invokeParams.Filter = @($thisTable.DescriptionField, '-like', $Description) + if ( $thisParams.Filter ) { + $thisParams.Filter += 'and' + # $null = $thisParams.Filter.Add('and') } + $thisParams.Filter += , @($thisTable.DescriptionField, '-like', $Description) + # $null = $thisParams.Filter.Add(@($thisTable.DescriptionField, '-like', $Description)) } - $addedSysIdProp = $false - # we need the sys_id value in order to get custom var data - # add it in if specific properties were requested and not part of the list - if ( $IncludeCustomVariable ) { - if ( $Property -and 'sys_id' -notin $Property ) { - $invokeParams.Property += 'sys_id' - $addedSysIdProp = $true - } - } + $thisParams.Table = $thisTable.Name # should use Get-ServiceNowAttachment, but put this here for ease of access if ( $thisTable.Name -eq 'attachment' ) { Write-Warning 'For attachments, use Get-ServiceNowAttachment' - $null = $invokeParams.Remove('Table') - $invokeParams.UriLeaf = '/attachment' + $null = $thisParams.Remove('Table') + $thisParams.UriLeaf = '/attachment' } - [array]$result = Invoke-ServiceNowRestMethod @invokeParams + [array]$result = Invoke-ServiceNowRestMethod @thisParams if ( -not $result ) { return @@ -340,7 +340,7 @@ function Get-ServiceNowRecord { $customVarParams = @{ Table = 'sc_item_option_mtom' Filter = @('request_item', '-eq', $recordSysId), 'and', @('sc_item_option.item_option_new.type', '-in', '1,2,3,4,5,6,7,8,9,10,16,18,21,22,26') - Property = 'sc_item_option.item_option_new.name', 'sc_item_option.value', 'sc_item_option.item_option_new.type', 'sc_item_option.item_option_new.question_text', 'sc_item_option.item_option_new.reference' + Property = 'sc_item_option.item_option_new.sys_name', 'sc_item_option.item_option_new.name', 'sc_item_option.value', 'sc_item_option.sys_id', 'sc_item_option.item_option_new.type', 'sc_item_option.item_option_new.question_text', 'sc_item_option.item_option_new.reference' IncludeTotalCount = $true ServiceNowSession = $ServiceNowSession } @@ -354,17 +354,29 @@ function Get-ServiceNowRecord { foreach ($var in $customVarsOut) { $newVar = [pscustomobject] @{ + Name = if ($var.'sc_item_option.item_option_new.name') { $var.'sc_item_option.item_option_new.name' } else { $var.'sc_item_option.item_option_new.sys_name' } Value = $var.'sc_item_option.value' DisplayName = $var.'sc_item_option.item_option_new.question_text' Type = $var.'sc_item_option.item_option_new.type' + SysId = $var.'sc_item_option.sys_id' } # show the underlying value if the option is a reference type - if ($newVar.Type -eq 'Reference' ) { - $newVar.Value = (Get-ServiceNowRecord -Table $var.'sc_item_option.item_option_new.reference' -ID $var.'sc_item_option.value' -Property name -AsValue -ServiceNowSession $ServiceNowSession) + if ( $newVar.Type -eq 'Reference' ) { + $newVar | Add-Member @{'ReferenceTable' = $var.'sc_item_option.item_option_new.reference' } + # issue 234. ID might not be sysid or number for reference...odd + $refValue = Get-ServiceNowRecord -Table $var.'sc_item_option.item_option_new.reference' -ID $var.'sc_item_option.value' -Property name -AsValue -ServiceNowSession $ServiceNowSession -ErrorAction SilentlyContinue + if ( $refValue ) { + $newVar.Value = $refValue + } } - $record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.name' = $newVar } + if ( $var.'sc_item_option.item_option_new.name' ) { + $record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.name' = $newVar } + } + else { + $record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.question_text' = $newVar } + } } if ( $addedSysIdProp ) { @@ -374,7 +386,6 @@ function Get-ServiceNowRecord { $record } } - } else { diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index b84fe21..e8bf90b 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -1,76 +1,79 @@ -function New-ServiceNowChangeRequest { - <# - .SYNOPSIS - Generates a new ServiceNow change request +<# +.SYNOPSIS + Generates a new ServiceNow change request + +.DESCRIPTION + Generates a new ServiceNow change request directly with values or via a change model or template. - .DESCRIPTION - Generates a new ServiceNow change request directly with values or via a change model or template. +.PARAMETER ModelID + Name or sys_id of the change model to use - .PARAMETER ModelID - Name or sys_id of the change model to use +.PARAMETER TemplateID + Name or sys_id of the standard change template to use - .PARAMETER TemplateID - Name of sys_id of the standard change template to use +.PARAMETER Caller + Full name or sys_id of the caller - .PARAMETER Caller - Full name or sys_id of the caller +.PARAMETER ShortDescription + Short description - .PARAMETER ShortDescription - Short description +.PARAMETER Description + Long description - .PARAMETER Description - Long description +.PARAMETER AssignmentGroup + Full name or sys_id of the assignment group - .PARAMETER AssignmentGroup - Full name or sys_id of the assignment group +.PARAMETER Comment + Comment to include - .PARAMETER Comment - Comment to include +.PARAMETER Category + Category name - .PARAMETER Category - Category name +.PARAMETER Subcategory + Subcategory name - .PARAMETER Subcategory - Subcategory name +.PARAMETER ConfigurationItem + Full name or sys_id of the configuration item to be associated with the change - .PARAMETER ConfigurationItem - Full name or sys_id of the configuration item to be associated with the change +.PARAMETER InputData + Field values which aren't one of the built in function properties - .PARAMETER CustomField - Custom field values which aren't one of the built in function properties +.PARAMETER ServiceNowSession + ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. - .PARAMETER Connection - Azure Automation Connection object containing username, password, and URL for the ServiceNow instance +.PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance - .PARAMETER PassThru - If provided, the new record will be returned +.PARAMETER PassThru + If provided, the new record will be returned - .EXAMPLE - New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' +.EXAMPLE + New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' - Create a basic change request + Create a basic change request - .EXAMPLE - New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' -CustomField @{'urgency'='1'} +.EXAMPLE + New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' -InputData @{'urgency'='1'} - Create a basic change request with custom fields + Create a basic change request with other fields - .EXAMPLE - New-ServiceNowChangeRequest -TemplateID 'Change VLAN on a Cisco switchport - 1' +.EXAMPLE + New-ServiceNowChangeRequest -TemplateID 'Change VLAN on a Cisco switchport - 1' - Create a change request from a standard change template + Create a change request from a standard change template - .EXAMPLE - New-ServiceNowChangeRequest -ModelID 'Normal' -ShortDescription 'make this change' -ConfigurationItem dbserver1 +.EXAMPLE + New-ServiceNowChangeRequest -ModelID 'Normal' -ShortDescription 'make this change' -ConfigurationItem dbserver1 - Create a change request from a change model + Create a change request from a change model - .EXAMPLE - New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' -PassThru +.EXAMPLE + New-ServiceNowChangeRequest -Caller 'Greg Brownstein' -ShortDescription 'New change request' -PassThru - Create a change request and return the newly created record + Create a change request and return the newly created record - #> + #> +function New-ServiceNowChangeRequest { [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'direct')] @@ -107,7 +110,7 @@ function New-ServiceNowChangeRequest { [parameter()] [Alias('CustomFields')] - [hashtable] $CustomField, + [hashtable] $InputData, [Parameter()] [Hashtable] $Connection, @@ -125,25 +128,25 @@ function New-ServiceNowChangeRequest { $values = @{} Switch ($PSBoundParameters.Keys) { - AssignmentGroup { $values['assignment_group'] = $PSBoundParameters.AssignmentGroup } - Caller { $values['caller_id'] = $PSBoundParameters.Caller } - Category { $values['category'] = $PSBoundParameters.Category } - Comment { $values['comments'] = $PSBoundParameters.Comment } - ConfigurationItem { $values['cmdb_ci'] = $PSBoundParameters.ConfigurationItem } - Description { $values['description'] = $PSBoundParameters.Description } - ShortDescription { $values['short_description'] = $PSBoundParameters.ShortDescription } - Subcategory { $values['subcategory'] = $PSBoundParameters.Subcategory } - ModelID { $values['chg_model'] = $PSBoundParameters.ModelID } - TemplateID { $values['std_change_producer_version'] = $PSBoundParameters.TemplateID; $values['type'] = 'Standard' } + AssignmentGroup { $values['assignment_group'] = $AssignmentGroup } + Caller { $values['caller_id'] = $Caller } + Category { $values['category'] = $Category } + Comment { $values['comments'] = $Comment } + ConfigurationItem { $values['cmdb_ci'] = $ConfigurationItem } + Description { $values['description'] = $Description } + ShortDescription { $values['short_description'] = $ShortDescription } + Subcategory { $values['subcategory'] = $Subcategory } + ModelID { $values['chg_model'] = $ModelID } + TemplateID { $values['std_change_producer_version'] = $TemplateID; $values['type'] = 'Standard' } } # add custom fields - $duplicateValues = ForEach ($Key in $CustomField.Keys) { + $duplicateValues = ForEach ($Key in $InputData.Keys) { If ( $values.ContainsKey($Key) ) { $Key } Else { - $values.Add($Key, $CustomField[$Key]) + $values.Add($Key, $InputData[$Key]) } } diff --git a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 index 8bdd91d..801cb6d 100644 --- a/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 +++ b/ServiceNow/Public/New-ServiceNowConfigurationItem.ps1 @@ -26,9 +26,9 @@ .PARAMETER Connection Azure Automation Connection object containing username, password, and URL for the ServiceNow instance -.PARAMETER ServiceNowSession +.PARAMETER ServiceNowSession ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. - + .EXAMPLE New-ServiceNowConfigurationItem -Name 'MyServer' -Class cmdb_ci_server Create a new CI @@ -55,14 +55,12 @@ function New-ServiceNowConfigurationItem { [parameter()] [string] $OperationalStatus, - # custom fields as hashtable [parameter()] [hashtable] $CustomField, [Parameter()] [switch] $PassThru, - #Azure Automation Connection object containing username, password, and URL for the ServiceNow instance [Parameter(ParameterSetName = 'UseConnectionObject', Mandatory)] [ValidateNotNullOrEmpty()] [Hashtable] $Connection, diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index b53fdf4..bd6e206 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -3,7 +3,43 @@ Generates a new ServiceNow Incident .DESCRIPTION -Generates a new ServiceNow Incident using predefined or custom fields by invoking the ServiceNow API +Generates a new ServiceNow Incident using predefined or other field values + +.PARAMETER Caller + Full name or sys_id of the caller + +.PARAMETER ShortDescription + Short description + +.PARAMETER Description + Long description + +.PARAMETER AssignmentGroup + Full name or sys_id of the assignment group + +.PARAMETER Comment + Comment to include + +.PARAMETER Category + Category name + +.PARAMETER Subcategory + Subcategory name + +.PARAMETER ConfigurationItem + Full name or sys_id of the configuration item to be associated with the change + +.PARAMETER InputData + Field values which aren't one of the built in function properties + +.PARAMETER ServiceNowSession +ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. + +.PARAMETER Connection + Azure Automation Connection object containing username, password, and URL for the ServiceNow instance + +.PARAMETER PassThru + If provided, the new record will be returned .EXAMPLE Generate a basic Incident attributed to the caller "UserName" with descriptions, categories, assignment groups and CMDB items set. @@ -20,7 +56,7 @@ Generate a basic Incident attributed to the caller "UserName" with descriptions, Category = "Office" Subcategory = "Outlook" ConfigurationItem = "UserPC1" - CustomFields = @{u_custom1 = "Custom Field Entry" + InputData = @{u_custom1 = "Custom Field Entry" u_another_custom = "Related Test"} } New-ServiceNowIncident @IncidentParams @@ -32,42 +68,33 @@ function New-ServiceNowIncident { Param( - # sys_id of the caller of the incident (user Get-ServiceNowUser to retrieve this) [parameter(Mandatory)] [string] $Caller, - # Short description of the incident [parameter(Mandatory)] [string] $ShortDescription, - # Long description of the incident [parameter()] [string] $Description, - # sys_id of the assignment group (use Get-ServiceNowUserGroup to retrieve this) [parameter()] [string] $AssignmentGroup, - # Comment to include in the ticket [parameter()] [string] $Comment, - # Category of the incident (e.g. 'Network') [parameter()] [string] $Category, - # Subcategory of the incident (e.g. 'Network') [parameter()] [string] $Subcategory, - # sys_id of the configuration item of the incident [parameter()] [string] $ConfigurationItem, - # custom fields as hashtable [parameter()] [Alias('CustomFields')] - [hashtable] $CustomField, + [hashtable] $InputData, [Parameter()] [Hashtable] $Connection, @@ -82,61 +109,51 @@ function New-ServiceNowIncident { begin {} process { - # Create a hash table of any defined parameters (not CustomField) that have values - $DefinedIncidentParameters = @('AssignmentGroup', 'Caller', 'Category', 'Comment', 'ConfigurationItem', 'Description', 'ShortDescription', 'Subcategory') - $TableEntryValues = @{} - ForEach ($Parameter in $DefinedIncidentParameters) { - If ($null -ne $PSBoundParameters.$Parameter) { - # Turn the defined parameter name into the ServiceNow attribute name - $KeyToAdd = Switch ($Parameter) { - AssignmentGroup { 'assignment_group'; break } - Caller { 'caller_id'; break } - Category { 'category'; break } - Comment { 'comments'; break } - ConfigurationItem { 'cmdb_ci'; break } - Description { 'description'; break } - ShortDescription { 'short_description'; break } - Subcategory { 'subcategory'; break } - } - $TableEntryValues.Add($KeyToAdd, $PSBoundParameters.$Parameter) - } + $values = @{} + Switch ($PSBoundParameters.Keys) { + AssignmentGroup { $values['assignment_group'] = $AssignmentGroup } + Caller { $values['caller_id'] = $Caller } + Category { $values['category'] = $Category } + Comment { $values['comments'] = $Comment } + ConfigurationItem { $values['cmdb_ci'] = $ConfigurationItem } + Description { $values['description'] = $Description } + ShortDescription { $values['short_description'] = $ShortDescription } + Subcategory { $values['subcategory'] = $Subcategory } + ModelID { $values['chg_model'] = $ModelID } + TemplateID { $values['std_change_producer_version'] = $TemplateID; $values['type'] = 'Standard' } } - # Add CustomField hash pairs to the Table Entry Values hash table - If ($null -ne $PSBoundParameters.CustomField) { - $DuplicateTableEntryValues = ForEach ($Key in $CustomField.Keys) { - If (($TableEntryValues.ContainsKey($Key) -eq $False)) { - # Add the unique entry to the table entry values hash table - $TableEntryValues.Add($Key, $CustomField[$Key]) - } - Else { - # Capture the duplicate key name - $Key - } + # add custom fields + $duplicateValues = ForEach ($Key in $InputData.Keys) { + If ( $values.ContainsKey($Key) ) { + $Key + } + Else { + $values.Add($Key, $InputData[$Key]) } } # Throw an error if duplicate fields were provided - If ($null -ne $DuplicateTableEntryValues) { - $DuplicateKeyList = $DuplicateTableEntryValues -join "," - Throw "Ticket fields may only be used once: $DuplicateKeyList" + If ( $duplicateValues ) { + Throw ('Fields may only be used once and the following were duplicated: {0}' -f $duplicateValues -join ",") } # Table Entry Splat $params = @{ - Method = 'Post' Table = 'incident' - Values = $TableEntryValues + Values = $values Connection = $Connection ServiceNowSession = $ServiceNowSession + PassThru = $true } - If ( $PSCmdlet.ShouldProcess($ShortDescription, 'Create new incident') ) { - $response = Invoke-ServiceNowRestMethod @params - If ($PassThru.IsPresent) { + If ( $PSCmdlet.ShouldProcess($ShortDescription, 'Create new Incident') ) { + $response = New-ServiceNowRecord @params + If ( $PassThru ) { $response.PSObject.TypeNames.Insert(0, "ServiceNow.Incident") $response } } } } + diff --git a/ServiceNow/Public/New-ServiceNowQuery.ps1 b/ServiceNow/Public/New-ServiceNowQuery.ps1 index e9403cf..5632f5f 100644 --- a/ServiceNow/Public/New-ServiceNowQuery.ps1 +++ b/ServiceNow/Public/New-ServiceNowQuery.ps1 @@ -69,234 +69,182 @@ function New-ServiceNowQuery { [OutputType([System.String])] param( - # Machine name of the field to order by - [parameter(ParameterSetName = 'Basic')] - [string] $OrderBy = 'opened_at', + [parameter()] + [object[]] $Filter, - # Direction of ordering (Desc/Asc) - [parameter(ParameterSetName = 'Basic')] - [ValidateSet("Desc", "Asc")] - [string] $OrderDirection = 'Desc', - - # Hashtable containing machine field names and values returned must match exactly (will be combined with AND) - [parameter(ParameterSetName = 'Basic')] - [hashtable] $MatchExact, - - # Hashtable containing machine field names and values returned rows must contain (will be combined with AND) - [parameter(ParameterSetName = 'Basic')] - [hashtable] $MatchContains, - - [parameter(ParameterSetName = 'Advanced')] - [System.Collections.ArrayList] $Filter, - - [parameter(ParameterSetName = 'Advanced')] - [System.Collections.ArrayList] $Sort + [parameter()] + [object[]] $Sort ) Write-Verbose ('{0} - {1}' -f $MyInvocation.MyCommand, $PSCmdlet.ParameterSetName) - if ( $PSCmdlet.ParameterSetName -eq 'Advanced' ) { - if ( $Filter ) { - $filterList = $Filter - # see if we're working with 1 array or multidimensional array - # we want multidimensional so convert if not - if ($Filter[0].GetType().Name -eq 'String') { - $filterList = @(, $Filter) - } - - $query = for ($i = 0; $i -lt $filterList.Count; $i++) { - $thisFilter = $filterList[$i] + if ( $Filter ) { - # allow passing of string instead of array - # useful for joins - if ($thisFilter.GetType().Name -eq 'String') { - $thisFilter = @(, $thisFilter) - } - - switch ($thisFilter.Count) { - 0 { - # nothing to see here - Continue - } + if ( $Filter[0].GetType().Name -eq 'Object[]' ) { + # already the format we want + $filterList = $Filter + } + else { + # change to array object as opposed to traditional array + $filterList = , $Filter + } - 1 { - # should be a join + $query = for ($i = 0; $i -lt $filterList.Count; $i++) { + $thisFilter = $filterList[$i] - switch ($thisFilter[0]) { - { $_ -in 'and', '-and' } { - '^' - } + # allow passing of string instead of array + # useful for joins + if ($thisFilter.GetType().Name -eq 'String') { + $thisFilter = @(, $thisFilter) + } - { $_ -in 'or', '-or' } { - '^OR' - } + switch ($thisFilter.Count) { + 0 { + # nothing to see here + Continue + } - { $_ -in 'group', '-group' } { - '^NQ' - } + 1 { + # should be a join - Default { - throw "Unsupported join operator '$($thisFilter[0])'. 'and', 'or', and 'group' are supported." - } + switch ($thisFilter[0]) { + { $_ -in 'and', '-and' } { + '^' } - # make sure we don't end on a join - if ( $i -eq $filterList.Count - 1) { - throw '$Filter cannot end with a join' + { $_ -in 'or', '-or' } { + '^OR' } - break - } - - { $_ -ne 1 } { - # perform data validation on all filters other than a join operator - $thisOperator = $script:ServiceNowOperator | Where-Object { $_.Name -eq $thisFilter[1] } - if ( -not $thisOperator ) { - throw ('Operator ''{0}'' is not valid' -f $thisFilter[1]) - } - if ( $thisOperator.NumValues -ne $thisFilter.Count - 2 ) { - throw ('Operator ''{0}'' requires 1 field name and {1} value(s)' -f $thisFilter[1], $thisOperator.NumValues) + { $_ -in 'group', '-group' } { + '^NQ' } - } - - 2 { - # should be a non-value operator, eg. ='' / ISEMPTY - '{0}{1}' -f $thisFilter[0], $thisOperator.QueryOperator - break - } - 3 { - # should be format - field operator value - - if ( $thisFilter[2] -is [DateTime] ) { - $dateGen = "'{0}','{1}'" -f $thisFilter[2].ToString('yyyy-MM-dd'), $thisFilter[2].ToString('HH:mm:ss') - '{0}{1}javascript:gs.dateGenerate({2})' -f $thisFilter[0], $thisOperator.QueryOperator, $dateGen - } - else { - '{0}{1}{2}' -f $thisFilter[0], $thisOperator.QueryOperator, $thisFilter[2] + Default { + throw "Unsupported join operator '$($thisFilter[0])'. 'and', 'or', and 'group' are supported." } - - break } - 4 { - # should be format - field operator value1 value2, where applicable, eg. between + # make sure we don't end on a join + if ( $i -eq $filterList.Count - 1) { + throw '$Filter cannot end with a join' + } - if ( $thisFilter[2] -is [DateTime] ) { - $dateGen1 = "'{0}','{1}'" -f $thisFilter[2].ToString('yyyy-MM-dd'), $thisFilter[2].ToString('HH:mm:ss') - $dateGen2 = "'{0}','{1}'" -f $thisFilter[3].ToString('yyyy-MM-dd'), $thisFilter[3].ToString('HH:mm:ss') - '{0}{1}javascript:gs.dateGenerate({2})@javascript:gs.dateGenerate({3})' -f $thisFilter[0], $thisOperator.QueryOperator, $dateGen1, $dateGen2 - } - else { - '{0}{1}{2}@{3}' -f $thisFilter[0], $thisOperator.QueryOperator, $thisFilter[2], $thisFilter[3] - } + break + } - break + { $_ -ne 1 } { + # perform data validation on all filters other than a join operator + $thisOperator = $script:ServiceNowOperator | Where-Object { $_.Name -eq $thisFilter[1] } + if ( -not $thisOperator ) { + throw ('Operator ''{0}'' is not valid' -f $thisFilter[1]) } - - Default { - throw ('Too many filter items for {0}, see the help' -f $thisFilter[0]) + if ( $thisOperator.NumValues -ne $thisFilter.Count - 2 ) { + throw ('Operator ''{0}'' requires 1 field name and {1} value(s)' -f $thisFilter[1], $thisOperator.NumValues) } } - } - } - - # force query to an array in case we only got one item and its a string - # otherwise below add to query won't work as expected - $query = @($query) - - if ($query) { - $query += '^' - } - - $orderList = $Sort - if ( $Sort ) { - # see if we're working with 1 array or multidimensional array - # we want multidimensional so convert if not - if ($Sort[0].GetType().Name -eq 'String') { - $orderList = @(, $Sort) - } - } + 2 { + # should be a non-value operator, eg. ='' / ISEMPTY + '{0}{1}' -f $thisFilter[0], $thisOperator.QueryOperator + break + } - $query += for ($i = 0; $i -lt $orderList.Count; $i++) { - $thisOrder = $orderList[$i] - if ( $orderList.Count -gt 1 -and $i -gt 0 ) { - '^' - } + 3 { + # should be format - field operator value - switch ($thisOrder.Count) { - 0 { - # nothing to see here - Continue - } + if ( $thisFilter[2] -is [DateTime] ) { + $dateGen = "'{0}','{1}'" -f $thisFilter[2].ToString('yyyy-MM-dd'), $thisFilter[2].ToString('HH:mm:ss') + '{0}{1}javascript:gs.dateGenerate({2})' -f $thisFilter[0], $thisOperator.QueryOperator, $dateGen + } + else { + '{0}{1}{2}' -f $thisFilter[0], $thisOperator.QueryOperator, $thisFilter[2] + } - 1 { - # should be field, default to ascending - 'ORDERBY' - $thisOrder[0] + break } - 2 { - switch ($thisOrder[1]) { - 'asc' { - 'ORDERBY' - } - - 'desc' { - 'ORDERBYDESC' - } + 4 { + # should be format - field operator value1 value2, where applicable, eg. between - Default { - throw "Invalid order direction '$_'. Provide either 'asc' or 'desc'." - } + if ( $thisFilter[2] -is [DateTime] ) { + $dateGen1 = "'{0}','{1}'" -f $thisFilter[2].ToString('yyyy-MM-dd'), $thisFilter[2].ToString('HH:mm:ss') + $dateGen2 = "'{0}','{1}'" -f $thisFilter[3].ToString('yyyy-MM-dd'), $thisFilter[3].ToString('HH:mm:ss') + '{0}{1}javascript:gs.dateGenerate({2})@javascript:gs.dateGenerate({3})' -f $thisFilter[0], $thisOperator.QueryOperator, $dateGen1, $dateGen2 } - $thisOrder[0] + else { + '{0}{1}{2}@{3}' -f $thisFilter[0], $thisOperator.QueryOperator, $thisFilter[2], $thisFilter[3] + } + + break } Default { - throw ('Too many items for {0}, see the help' -f $thisOrder[0]) + throw ('Too many filter items for {0}, see the help' -f $thisFilter[0]) } } } + } - ($query -join '').Trim('^') + # force query to an array in case we only got one item and its a string + # otherwise below add to query won't work as expected + $query = @($query) + if ($query) { + $query += '^' } - else { - # Basic parameter set - # Create StringBuilder - $Query = New-Object System.Text.StringBuilder + $orderList = $Sort - # Start the query off with a order direction - $direction = Switch ($OrderDirection) { - 'Asc' { 'ORDERBY'; break } - Default { 'ORDERBYDESC' } + if ( $Sort ) { + # see if we're working with 1 array or multidimensional array + # we want multidimensional so convert if not + if ($Sort[0].GetType().Name -eq 'String') { + $orderList = @(, $Sort) } - [void]$Query.Append($direction) + } - # Add OrderBy - [void]$Query.Append($OrderBy) + $query += for ($i = 0; $i -lt $orderList.Count; $i++) { + $thisOrder = $orderList[$i] + if ( $orderList.Count -gt 1 -and $i -gt 0 ) { + '^' + } - # Build the exact matches into the query - If ($MatchExact) { - ForEach ($Field in $MatchExact.keys) { - $ExactString = "^{0}={1}" -f $Field.ToString().ToLower(), ($MatchExact.$Field) - [void]$Query.Append($ExactString) + switch ($thisOrder.Count) { + 0 { + # nothing to see here + Continue } - } - # Add the values which given fields should contain - If ($MatchContains) { - ForEach ($Field in $MatchContains.keys) { - $ContainsString = "^{0}LIKE{1}" -f $Field.ToString().ToLower(), ($MatchContains.$Field) - [void]$Query.Append($ContainsString) + 1 { + # should be field, default to ascending + 'ORDERBY' + $thisOrder[0] } - } - # Output StringBuilder to string - $Query.ToString() + 2 { + switch ($thisOrder[1]) { + 'asc' { + 'ORDERBY' + } + + 'desc' { + 'ORDERBYDESC' + } + + Default { + throw "Invalid order direction '$_'. Provide either 'asc' or 'desc'." + } + } + $thisOrder[0] + } + + Default { + throw ('Too many items for {0}, see the help' -f $thisOrder[0]) + } + } } + + ($query -join '').Trim('^') } \ No newline at end of file diff --git a/ServiceNow/Public/New-ServiceNowRecord.ps1 b/ServiceNow/Public/New-ServiceNowRecord.ps1 index bf3344d..6862894 100644 --- a/ServiceNow/Public/New-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/New-ServiceNowRecord.ps1 @@ -8,8 +8,8 @@ .PARAMETER Table Name or class name of the table to create the new record -.PARAMETER Values - Hashtable with all the key/value pairs for the new record +.PARAMETER InputData + Key/value pairs of fields and their values .PARAMETER PassThru If provided, the new record will be returned @@ -21,12 +21,17 @@ ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. .EXAMPLE - New-ServiceNowRecord -Table incident -Values @{'Caller'='me';'short_description'='my issue'} + New-ServiceNowRecord -Table incident -InputData @{'Caller'='me';'short_description'='my issue'} Create a new record in the incident table +.EXAMPLE + @{'short_description'='my issue';'assignment_group'='IT Support'}, @{'short_description'='another issue'} | New-ServiceNowRecord -Table incident + + Create multiple records in the same table by piping the input data + .INPUTS - None + InputData .OUTPUTS PSCustomObject if PassThru provided @@ -40,8 +45,9 @@ function New-ServiceNowRecord { [parameter(Mandatory)] [string] $Table, - [parameter(Mandatory)] - [hashtable] $Values, + [parameter(Mandatory, ValueFromPipeline)] + [Alias('Values')] + [hashtable] $InputData, [Parameter()] [Hashtable] $Connection, @@ -53,19 +59,27 @@ function New-ServiceNowRecord { [switch] $PassThru ) - $invokeParams = $PSBoundParameters - $null = $invokeParams.Remove('PassThru') + process { + + $params = @{ + Method = 'Post' + Table = $Table + Values = $InputData + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } - If ( $PSCmdlet.ShouldProcess($Table, 'Create new record') ) { + If ( $PSCmdlet.ShouldProcess($Table, 'Create new record') ) { - $response = Invoke-ServiceNowRestMethod @invokeParams -Method 'Post' + $response = Invoke-ServiceNowRestMethod @params - If ( $PassThru ) { - $type = $script:ServiceNowTable | Where-Object { $_.Name -eq $Table -or $_.ClassName -eq $Table } | Select-Object -ExpandProperty Type - if ($type) { - $response | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } + If ( $PassThru ) { + $type = $script:ServiceNowTable | Where-Object { $_.Name -eq $Table -or $_.ClassName -eq $Table } | Select-Object -ExpandProperty Type + if ($type) { + $response | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $type) } + } + $response } - $response } } } diff --git a/ServiceNow/Public/Remove-ServiceNowRecord.ps1 b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 index 41e9674..d96332e 100644 --- a/ServiceNow/Public/Remove-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Remove-ServiceNowRecord.ps1 @@ -1,19 +1,47 @@ +<# +.SYNOPSIS + Remove a record + +.DESCRIPTION + Remove a record + +.PARAMETER Table + Name of the table to be queried, by either table name or class name. Use tab completion for list of known tables. + You can also provide any table name ad hoc. + +.PARAMETER ID + Either the record sys_id or number. + If providing just an ID, not with Table, the ID prefix will be looked up to find the table name. + +.EXAMPLE + Remove-ServiceNowRecord CHG0123456 + + Removes a record + +.EXAMPLE + Remove-ServiceNowRecord CHG0123456 -Confirm:$false + + Removes a record without prompting for confirmation + +.EXAMPLE + Get-ServiceNowRecord -Table incident -Description 'not needed' | Remove-ServiceNowRecord + + Remove multiple records via pipeline +#> + function Remove-ServiceNowRecord { - [CmdletBinding(ConfirmImpact = 'High')] + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] Param( - # Table containing the entry we're deleting - [parameter(Mandatory, ValueFromPipelineByPropertyName)] - [ValidateNotNullOrEmpty()] + [parameter(ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, - # sys_id of the entry we're deleting [parameter(Mandatory, ValueFromPipelineByPropertyName)] [ValidateNotNullOrEmpty()] - [Alias('sys_id')] - [string] $SysId, + [Alias('sys_id', 'SysId', 'number')] + [string] $ID, [Parameter()] [Hashtable] $Connection, @@ -22,19 +50,21 @@ function Remove-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - begin { + process { - } + $thisTable, $thisID = Invoke-TableIdLookup -T $Table -I $ID -AsSysId -C $Connection -S $ServiceNowSession - process { - $params = @{ - Method = 'Delete' - Table = $Table - SysId = $SysId - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } + If ($PSCmdlet.ShouldProcess("$($thisTable.ClassName) $ID", 'Remove record')) { - Invoke-ServiceNowRestMethod @params + $params = @{ + Method = 'Delete' + Table = $thisTable.Name + SysId = $thisID + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + + Invoke-ServiceNowRestMethod @params + } } } diff --git a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 deleted file mode 100644 index 3b83b1d..0000000 --- a/ServiceNow/Public/Update-ServiceNowChangeRequest.ps1 +++ /dev/null @@ -1,50 +0,0 @@ -<# -.EXAMPLE - Update-ServiceNowChangeRequest -Values @{ 'state' = 3 } -SysId -#> -function Update-ServiceNowChangeRequest { - - [CmdletBinding(SupportsShouldProcess)] - - Param( - # sys_id of the caller of the incident (use Get-ServiceNowUser to retrieve this) - [parameter(Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $SysId, - - # Hashtable of values to use as the record's properties - [parameter(Mandatory)] - [hashtable]$Values, - - [Parameter()] - [Hashtable] $Connection, - - [Parameter()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession, - - [Parameter()] - [switch] $PassThru - ) - - begin {} - - process { - $params = @{ - Method = 'Patch' - Table = 'change_request' - SysId = $SysId - Values = $Values - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - - If ($PSCmdlet.ShouldProcess("Change request $SysID", 'Update values')) { - $response = Invoke-ServiceNowRestMethod @params - if ( $PassThru.IsPresent ) { - $response - } - } - } - - end {} -} diff --git a/ServiceNow/Public/Update-ServiceNowIncident.ps1 b/ServiceNow/Public/Update-ServiceNowIncident.ps1 deleted file mode 100644 index dd2fe0b..0000000 --- a/ServiceNow/Public/Update-ServiceNowIncident.ps1 +++ /dev/null @@ -1,47 +0,0 @@ -function Update-ServiceNowIncident { - - [CmdletBinding(SupportsShouldProcess)] - - Param - ( # sys_id of the caller of the incident (use Get-ServiceNowUser to retrieve this) - [parameter(Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $SysId, - - # Hashtable of values to use as the record's properties - [parameter(Mandatory)] - [hashtable] $Values, - - [Parameter()] - [Hashtable] $Connection, - - [Parameter()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession, - - [Parameter()] - [switch] $PassThru - ) - - begin {} - - process { - $params = @{ - Method = 'Patch' - Table = 'incident' - SysId = $SysId - Values = $Values - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - - If ($PSCmdlet.ShouldProcess("Incident $SysID", 'Update values')) { - $response = Invoke-ServiceNowRestMethod @params - if ( $PassThru.IsPresent ) { - $response - } - } - } - - end {} -} - diff --git a/ServiceNow/Public/Update-ServiceNowRecord.ps1 b/ServiceNow/Public/Update-ServiceNowRecord.ps1 index a4748b3..c1a2ca8 100644 --- a/ServiceNow/Public/Update-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRecord.ps1 @@ -11,10 +11,14 @@ .PARAMETER ID Either the record sys_id or number. - If providing just an Id, not with Table, the Id prefix will be looked up to find the table name. + If providing just an ID, not with Table, the ID prefix will be looked up to find the table name. -.PARAMETER Values - Hashtable with all the field/value pairs for the updated record +.PARAMETER InputData + Key/value pairs of fields and their values + +.PARAMETER CustomVariableData + Key/value pairs of custom variable names and their values. + Get custom variable names with Get-ServiceNowRecord -IncludeCustomVariable. .PARAMETER PassThru If provided, the updated record will be returned @@ -26,19 +30,29 @@ ServiceNow session created by New-ServiceNowSession. Will default to script-level variable $ServiceNowSession. .EXAMPLE - Update-ServiceNowRecord -ID 'INC0010001' -Values @{State = 'Closed'} + Update-ServiceNowRecord -ID 'INC0010001' -InputData @{State = 'Closed'} + Update a record by number. The table name will be looked up based on the prefix. .EXAMPLE - Update-ServiceNowRecord -Table 'change_request' -ID 'CHG0010001' -Values @{'work_notes' = 'my notes'} + Update-ServiceNowRecord -Table 'change_request' -ID 'CHG0010001' -InputData @{'work_notes' = 'my notes'} + Update a record by number. The table name is provided directly as the table lookup is different, 'Change Request' as opposed to 'change_request'. .EXAMPLE - Update-ServiceNowRecord -Table incident -ID '13378afb-97a6-451a-b1ec-2c9e85313188' -Values @{State = 'Closed'} + Update-ServiceNowRecord -Table incident -ID '13378afb-97a6-451a-b1ec-2c9e85313188' -InputData @{State = 'Closed'} + Update a record by table name and sys_id. + Providing a sys_id as opposed to a number minimizes the api calls. + +.EXAMPLE + Get-ServiceNowRecord INC0000001 | Update-ServiceNowRecord -InputData @{'work_notes' = 'Updated by PowerShell'} + + Update details piping an existing object. You do not need to specify the table or ID for the update. .EXAMPLE - Get-ServiceNowRecord INC0000001 | Update-ServiceNowRecord -Values @{work_notes = "Updated by PowerShell"} + Update-ServiceNowRecord -ID RITM0000001 -CustomVariableData @{'question' = 'Yes'} + Update details piping an existing object. You do not need to specify the table or ID for the update. .INPUTS @@ -50,19 +64,26 @@ function Update-ServiceNowRecord { - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'field')] Param( [parameter(ValueFromPipelineByPropertyName)] [Alias('sys_class_name')] [string] $Table, + # validation not needed as Invoke-TableIdLookup will handle it with -AsSysId [Parameter(Mandatory, ValueFromPipelineByPropertyName)] [Alias('sys_id', 'SysId', 'number')] [string] $ID, - [parameter(Mandatory)] - [hashtable] $Values, + [parameter(Mandatory, ParameterSetName = 'both')] + [parameter(Mandatory, ParameterSetName = 'field')] + [Alias('Values')] + [hashtable] $InputData, + + [parameter(Mandatory, ParameterSetName = 'both')] + [parameter(Mandatory, ParameterSetName = 'custom')] + [hashtable] $CustomVariableData, [Parameter()] [switch] $PassThru, @@ -74,70 +95,62 @@ function Update-ServiceNowRecord { [hashtable] $ServiceNowSession = $script:ServiceNowSession ) - begin {} - process { - if ( $ID -match '[a-zA-Z0-9]{32}' ) { - $sysId = $ID - if ( $Table ) { - $tableName = $Table - } - else { - Write-Error 'Providing a sys_id for -ID requires a value for -Table' - } + $thisTable, $thisID = Invoke-TableIdLookup -T $Table -I $ID -AsSysId -C $Connection -S $ServiceNowSession + + If (-not $PSCmdlet.ShouldProcess("$($thisTable.ClassName) $ID", 'Update values')) { + return } - else { - # get needed details, table name and sys_id, for update - $getParams = @{ - Id = $ID - Property = 'sys_class_name', 'sys_id', 'number' + + if ( $PSBoundParameters.ContainsKey('InputData') ) { + + $params = @{ + Method = 'Patch' + Table = $thisTable.Name + SysId = $thisID + Values = $InputData Connection = $Connection ServiceNowSession = $ServiceNowSession } - if ( $Table ) { - $getParams.Table = $Table - } + $response = Invoke-ServiceNowRestMethod @params + } - $thisRecord = Get-ServiceNowRecord @getParams + if ( $PSBoundParameters.ContainsKey('CustomVariableData') ) { - if ( -not $thisRecord ) { - Write-Error ('Record not found for ID ''{0}''' -f $ID) - continue - } + $customVarsOut = Get-ServiceNowRecord -Table $thisTable.Name -ID $thisID -IncludeCustomVariable -Property sys_id, number -Connection $Connection -ServiceNowSession $ServiceNowSession | Select-Object -ExpandProperty CustomVariable - # if the table name was provided, use it - # otherwise use the table name we retrieved which may or may not work - if ( $Table ) { - $tableName = $Table - } - else { - $tableName = $thisRecord.sys_class_name - } - $sysId = $thisRecord.sys_id - } + foreach ($key in $CustomVariableData.Keys) { - $newTableName = $script:ServiceNowTable | Where-Object { $_.Name.ToLower() -eq $tableName.ToLower() -or $_.ClassName.ToLower() -eq $tableName.ToLower() } | Select-Object -ExpandProperty Name - if ( -not $newTableName ) { - # we aren't aware of this table in our config so use as is - $newTableName = $tableName - } + $thisCustomVar = $customVarsOut.PSObject.Properties.Value | Where-Object { $key -in $_.Name, $_.DisplayName, $_.SysId } - $params = @{ - Method = 'Patch' - Table = $newTableName - SysId = $sysId - Values = $Values - Connection = $Connection - ServiceNowSession = $ServiceNowSession + if ( $thisCustomVar ) { + $params = @{ + Method = 'Patch' + Table = 'sc_item_option' + SysId = $thisCustomVar.SysId + Values = @{'value' = $CustomVariableData[$key] } + Connection = $Connection + ServiceNowSession = $ServiceNowSession + } + $null = Invoke-ServiceNowRestMethod @params + } + else { + Write-Warning ('Custom variable {0} not found' -f $key) + } + } } - If ($PSCmdlet.ShouldProcess("$newTableName $sysId", 'Update values')) { - $response = Invoke-ServiceNowRestMethod @params - if ( $PassThru ) { - $response + if ( $PassThru ) { + if ( $PSBoundParameters.ContainsKey('CustomVariableData') ) { + $response = Get-ServiceNowRecord -Table $thisTable.Name -ID $thisID -IncludeCustomVariable -Connection $Connection -ServiceNowSession $ServiceNowSession + } + + if ($thisTable.Type) { + $response | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $thisTable.Type) } } + $response } } } diff --git a/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 b/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 deleted file mode 100644 index caa80ff..0000000 --- a/ServiceNow/Public/Update-ServiceNowRequestedItem.ps1 +++ /dev/null @@ -1,69 +0,0 @@ -function Update-ServiceNowRequestItem { - <# - .SYNOPSIS - Update an existing request item (RITM) - - .DESCRIPTION - Update an existing request item (RITM) - - .EXAMPLE - Update-ServiceNowRequestItem -SysId $SysId -Values @{property='value'} - - Updates a ticket number with a value providing no return output. - - .EXAMPLE - Update-ServiceNowRequestItem -SysId $SysId -Values @{property='value'} -PassThru - - Updates a ticket number with a value providing return output. - - .NOTES - - #> - - [OutputType([void], [System.Management.Automation.PSCustomObject])] - [CmdletBinding(SupportsShouldProcess)] - - Param ( - # sys_id of the ticket to update - [parameter(Mandatory, ValueFromPipelineByPropertyName)] - [Alias('sys_id')] - [string] $SysId, - - # Hashtable of values to use as the record's properties - [Parameter(Mandatory)] - [hashtable] $Values, - - [Parameter()] - [Hashtable] $Connection, - - [Parameter()] - [hashtable] $ServiceNowSession = $script:ServiceNowSession, - - [Parameter()] - [switch] $PassThru - ) - - begin {} - - process { - - $params = @{ - Method = 'Patch' - Table = 'sc_req_item' - SysId = $SysId - Values = $Values - Connection = $Connection - ServiceNowSession = $ServiceNowSession - } - - If ($PSCmdlet.ShouldProcess("Requested Item $SysID", 'Update values')) { - $response = Invoke-ServiceNowRestMethod @params - if ( $PassThru.IsPresent ) { - $response - } - } - - } - - end {} -} diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 58cdbb6..4e2efc6 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '3.4.3' +ModuleVersion = '4.0' # Supported PSEditions # CompatiblePSEditions = @() @@ -21,7 +21,7 @@ ModuleVersion = '3.4.3' GUID = 'b90d67da-f8d0-4406-ad74-89d169cd0633' # Author of this module -Author = 'Sam Martin Rick Arroues Greg Brownstein' +Author = 'Greg Brownstein, Rick Arroues, Sam Martin' # Company or vendor of this module CompanyName = 'None' @@ -30,7 +30,7 @@ CompanyName = 'None' Copyright = '(c) 2015-2023 Snow-Shell. All rights reserved.' # Description of the functionality provided by this module -Description = 'Automate against ServiceNow service and asset management. This module can be used standalone or with Azure Automation.' +Description = 'Automate against ServiceNow service and asset management. This module can be used standalone, with Azure Automation, or Docker.' # Minimum version of the PowerShell engine required by this module # PowerShellVersion = '' @@ -69,19 +69,14 @@ FormatsToProcess = 'ServiceNow.format.ps1xml' NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Get-ServiceNowRecordInterim', 'New-ServiceNowConfigurationItem', +FunctionsToExport = 'New-ServiceNowConfigurationItem', 'Get-ServiceNowRecord', 'New-ServiceNowSession', 'Add-ServiceNowAttachment', 'Get-ServiceNowAttachment', - 'Export-ServiceNowAttachment', 'Get-ServiceNowChangeRequest', - 'Get-ServiceNowConfigurationItem', 'Get-ServiceNowIncident', - 'Get-ServiceNowRequest', 'Get-ServiceNowRequestedItem', - 'Get-ServiceNowTable', 'Get-ServiceNowTableEntry', - 'Get-ServiceNowUser', 'Get-ServiceNowUserGroup', + 'Export-ServiceNowAttachment', 'New-ServiceNowChangeRequest', 'New-ServiceNowIncident', 'New-ServiceNowQuery', 'New-ServiceNowRecord', 'Remove-ServiceNowAttachment', 'Remove-ServiceNowRecord', - 'Update-ServiceNowChangeRequest', 'Update-ServiceNowIncident', - 'Update-ServiceNowRequestedItem', 'Update-ServiceNowRecord', + 'Update-ServiceNowRecord', 'Export-ServiceNowRecord', 'Invoke-ServiceNowGraphQL', 'New-ServiceNowChangeTask' @@ -92,10 +87,7 @@ CmdletsToExport = @() VariablesToExport = 'ServiceNowSession', 'ServiceNowOperator', 'ServiceNowTable' # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. -AliasesToExport = 'gsnr', 'Get-ServiceNowIncident', 'Get-ServiceNowChangeRequest', - 'Get-ServiceNowConfigurationItem', 'Get-ServiceNowRequest', - 'Get-ServiceNowRequestedItem', 'Get-ServiceNowUser', - 'Get-ServiceNowUserGroup', 'Update-ServiceNowNumber' +AliasesToExport = 'gsnr' # DSC resources to export from this module # DscResourcesToExport = @() diff --git a/ServiceNow/ServiceNow.psm1 b/ServiceNow/ServiceNow.psm1 index 070c602..97fe40b 100644 --- a/ServiceNow/ServiceNow.psm1 +++ b/ServiceNow/ServiceNow.psm1 @@ -13,7 +13,8 @@ $tableArgCompleterSb = { $ServiceNowTable | ForEach-Object { if ( $_.ClassName ) { '''{0}''' -f $_.ClassName - } else { + } + else { '''{0}''' -f $_.Name } } @@ -25,7 +26,9 @@ $tableArgCompleterSb = { 'Get-ServiceNowAttachment', 'Add-ServiceNowAttachment', 'New-ServiceNowRecord', - 'Update-ServiceNowRecord' + 'Update-ServiceNowRecord', + 'Remove-ServiceNowRecord', + 'Export-ServiceNowRecord' ) | ForEach-Object { Register-ArgumentCompleter -CommandName $_ -ParameterName 'Table' -ScriptBlock $tableArgCompleterSb } @@ -49,12 +52,7 @@ $Script:ServiceNowSession = @{} Export-ModuleMember -Variable ServiceNowSession $aliases = @{ - 'Update-ServiceNowRequestItem' = 'Update-ServiceNowRequestedItem' - 'Remove-ServiceNowTableEntry' = 'Remove-ServiceNowRecord' - 'New-ServiceNowTableEntry' = 'New-ServiceNowRecord' - 'Update-ServiceNowTableEntry' = 'Update-ServiceNowRecord' - 'Update-ServiceNowNumber' = 'Update-ServiceNowRecord' - 'gsnr' = 'Get-ServiceNowRecord' + 'gsnr' = 'Get-ServiceNowRecord' } $aliases.GetEnumerator() | ForEach-Object { Set-Alias -Name $_.Key -Value $_.Value From 4366cfaeb34e31e8fd82dce1f446b32490308daf Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 16 Mar 2023 19:23:55 -0400 Subject: [PATCH 329/348] release prep --- RELEASE.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index c926f6a..866c6b1 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1 +1,13 @@ -- `Get-ServiceNowRecord`, custom variables of type Reference providing sysid instead of actual value, [#218](https://github.com/Snow-Shell/servicenow-powershell/issues/218) +- Add `Update-ServiceNowRecord -CustomVariableData` to update custom variable values, [#237](https://github.com/Snow-Shell/servicenow-powershell/issues/237) +- Add `New-ServiceNowChangeRequest` support for change models and standard change templates +- Fix 0 byte file error with `Add-ServiceNowAttachment`, [#241](https://github.com/Snow-Shell/servicenow-powershell/issues/241) +- `Get-ServiceNowRecord -New` has been deprecated and the new format is the only option +- `Update-ServiceNowChangeRequest`, `Update-ServiceNowincident`, and `Update-ServiceNowRequestedItem` deprecated. Use `Update-ServiceNowRecord`. The only difference was the table name and didn't make sense to maintain so many functions when documenting will do. `Update-ServiceNowRecord` has been enhanced as well so all updates can take advantage. +- `Get-ServiceNowRecordInterim` has been deprecated. +- Add generic `-Table` and `-ID` lookup function has been created and used across all functions where these parameters are used +- Add `-Table` tab ahead for `Remove-ServiceNowRecord` and `Export-ServiceNowRecord` +- Add `-ID` only lookup, no table name needed, for all +- Add/Update parameter sets to make it clearer when to use `-Table`, `-ID`, `-Filter`, etc +- Add pipeline support to `Export-ServiceNowRecord`, `New-ServiceNowRecord`, and `Update-ServiceNowRecord` +- Add `Get-ServiceNowRecord -ParentID` without providing `-Table` returns all tasks associated with that parent record +- Standardize parameter names across functions From 7616ab5b98c1a65ebb9fa6e876c9a2b533449ff4 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Thu, 16 Mar 2023 23:28:15 +0000 Subject: [PATCH 330/348] Update manifest to 4.0.0 --- CHANGELOG.md | 17 +++++++++++++++++ ServiceNow/ServiceNow.psd1 | 18 ++++++++---------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f736b..f6f69c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## 4.0.0 +- Add `Update-ServiceNowRecord -CustomVariableData` to update custom variable values, [#237](https://github.com/Snow-Shell/servicenow-powershell/issues/237) +- Add `New-ServiceNowChangeRequest` support for change models and standard change templates +- Fix 0 byte file error with `Add-ServiceNowAttachment`, [#241](https://github.com/Snow-Shell/servicenow-powershell/issues/241) +- `Get-ServiceNowRecord -New` has been deprecated and the new format is the only option +- `Update-ServiceNowChangeRequest`, `Update-ServiceNowincident`, and `Update-ServiceNowRequestedItem` deprecated. Use `Update-ServiceNowRecord`. The only difference was the table name and didn't make sense to maintain so many functions when documenting will do. `Update-ServiceNowRecord` has been enhanced as well so all updates can take advantage. +- `Get-ServiceNowRecordInterim` has been deprecated. +- Add generic `-Table` and `-ID` lookup function has been created and used across all functions where these parameters are used +- Add `-Table` tab ahead for `Remove-ServiceNowRecord` and `Export-ServiceNowRecord` +- Add `-ID` only lookup, no table name needed, for all +- Add/Update parameter sets to make it clearer when to use `-Table`, `-ID`, `-Filter`, etc +- Add pipeline support to `Export-ServiceNowRecord`, `New-ServiceNowRecord`, and `Update-ServiceNowRecord` +- Add `Get-ServiceNowRecord -ParentID` without providing `-Table` returns all tasks associated with that parent record +- Standardize parameter names across functions + + ## 3.4.3 - `Get-ServiceNowRecord`, custom variables of type Reference providing sysid instead of actual value, [#218](https://github.com/Snow-Shell/servicenow-powershell/issues/218) @@ -179,3 +195,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 4e2efc6..e01a7f4 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -1,9 +1,9 @@ # # Module manifest for module 'ServiceNow' # -# Generated by: Sam Martin Rick Arroues Greg Brownstein +# Generated by: Greg Brownstein, Rick Arroues, Sam Martin # -# Generated on: 12/17/2022 +# Generated on: 03/16/2023 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '4.0' +ModuleVersion = '4.0.0' # Supported PSEditions # CompatiblePSEditions = @() @@ -69,16 +69,14 @@ FormatsToProcess = 'ServiceNow.format.ps1xml' NestedModules = @() # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'New-ServiceNowConfigurationItem', - 'Get-ServiceNowRecord', 'New-ServiceNowSession', - 'Add-ServiceNowAttachment', 'Get-ServiceNowAttachment', - 'Export-ServiceNowAttachment', +FunctionsToExport = 'New-ServiceNowConfigurationItem', 'Get-ServiceNowRecord', + 'New-ServiceNowSession', 'Add-ServiceNowAttachment', + 'Get-ServiceNowAttachment', 'Export-ServiceNowAttachment', 'New-ServiceNowChangeRequest', 'New-ServiceNowIncident', 'New-ServiceNowQuery', 'New-ServiceNowRecord', 'Remove-ServiceNowAttachment', 'Remove-ServiceNowRecord', - 'Update-ServiceNowRecord', - 'Export-ServiceNowRecord', 'Invoke-ServiceNowGraphQL', - 'New-ServiceNowChangeTask' + 'Update-ServiceNowRecord', 'Export-ServiceNowRecord', + 'Invoke-ServiceNowGraphQL', 'New-ServiceNowChangeTask' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. CmdletsToExport = @() From 829fce27dd3652d847ed66e588f21d1d3e814c50 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 17 Mar 2023 07:50:40 -0400 Subject: [PATCH 331/348] Update Readme.md --- Readme.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Readme.md b/Readme.md index 10d7af4..f77d039 100644 --- a/Readme.md +++ b/Readme.md @@ -58,32 +58,35 @@ All examples below assume a new session has already been created. ### Getting incidents opened in the last 30 days ```PowerShell -$filter = @('opened_at', '-ge', (Get-Date).AddDays(-30)) -Get-ServiceNowRecord -Table incident -Filter $filter +Get-ServiceNowRecord -Table incident -Filter @('opened_at', '-ge', (Get-Date).AddDays(-30)) ``` ### Retrieving an Incident Containing the Word 'PowerShell' ```PowerShell -Get-ServiceNowRecord -Table incident -Filter @('short_description','-like','PowerShell') +Get-ServiceNowRecord -Table incident -Description 'powershell' ``` ### Update a Ticket ```PowerShell -Get-ServiceNowRecord -First 1 -Filter @('short_description','-eq','PowerShell') | Update-ServiceNowIncident -Values @{comments='Updated via PowerShell'} +Get-ServiceNowRecord -First 1 -Description 'powershell' | Update-ServiceNowRecord -InputData @{comments='Updated via PowerShell'} ``` ### Creating an Incident with custom table entries ```PowerShell -$IncidentParams = @{Caller = "UserName" - ShortDescription = "New PS Incident" - Description = "This incident was created from Powershell" - CustomFields = @{u_service = "MyService" - u_incident_type = "Request"} - } -New-ServiceNowIncident @Params +$params = @{ + Caller = "UserName" + ShortDescription = "New PS Incident" + Description = "This incident was created from Powershell" + InputData = @{ + u_service = "MyService" + u_incident_type = "Request" + urgency = 1 + } +} +New-ServiceNowIncident @params ``` ### Azure Connection Object (Automation Integration Module Support) From 7a58768dc0977b4b49e77e2098407fd6c0861fd2 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 17 Mar 2023 07:52:40 -0400 Subject: [PATCH 332/348] Update Readme.md --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index f77d039..06c7257 100644 --- a/Readme.md +++ b/Readme.md @@ -70,7 +70,7 @@ Get-ServiceNowRecord -Table incident -Description 'powershell' ### Update a Ticket ```PowerShell -Get-ServiceNowRecord -First 1 -Description 'powershell' | Update-ServiceNowRecord -InputData @{comments='Updated via PowerShell'} +Get-ServiceNowRecord inc0010002 | Update-ServiceNowRecord -InputData @{comments='Updated via PowerShell'} ``` ### Creating an Incident with custom table entries From dd206a77f53bd24db1e21d6493e408d12cff47c4 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 24 Jul 2023 08:04:38 -0400 Subject: [PATCH 333/348] BasicAuth fails when authentication profiles are active on ServiceNow #248 (#249) --- ServiceNow/Private/Get-ServiceNowAuth.ps1 | 31 +++++++++++++++-------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/ServiceNow/Private/Get-ServiceNowAuth.ps1 b/ServiceNow/Private/Get-ServiceNowAuth.ps1 index 31c6ae6..3bb0043 100644 --- a/ServiceNow/Private/Get-ServiceNowAuth.ps1 +++ b/ServiceNow/Private/Get-ServiceNowAuth.ps1 @@ -35,36 +35,45 @@ function Get-ServiceNowAuth { $hashOut.Headers = @{ 'Authorization' = 'Bearer {0}' -f $ServiceNowSession.AccessToken.GetNetworkCredential().password } - } else { - $hashOut.Credential = $ServiceNowSession.Credential + } + else { + # issue 248 + $pair = '{0}:{1}' -f $ServiceNowSession.Credential.UserName, $ServiceNowSession.Credential.GetNetworkCredential().Password + $hashOut.Headers = @{ Authorization = 'Basic ' + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair)) } } if ( $ServiceNowSession.Proxy ) { $hashOut.Proxy = $ServiceNowSession.Proxy if ( $ServiceNowSession.ProxyCredential ) { $hashOut.ProxyCredential = $ServiceNowSession.ProxyCredential - } else { + } + else { $hashOut.ProxyUseDefaultCredentials = $true } } - } elseif ( $Connection ) { + } + elseif ( $Connection ) { Write-Verbose 'connection' - $SecurePassword = ConvertTo-SecureString $Connection.Password -AsPlainText -Force - $Credential = New-Object System.Management.Automation.PSCredential ($Connection.Username, $SecurePassword) - $hashOut.Credential = $Credential + # issue 248 + $pair = '{0}:{1}' -f $Connection.Username, $Connection.Password + $hashOut.Headers = @{ Authorization = 'Basic ' + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair)) } $hashOut.Uri = 'https://{0}/api/now/v1' -f $Connection.ServiceNowUri - } elseif ( $env:SNOW_SERVER ) { + } + elseif ( $env:SNOW_SERVER ) { $hashOut.Uri = 'https://{0}/api/now' -f $env:SNOW_SERVER if ( $env:SNOW_TOKEN ) { $hashOut.Headers = @{ 'Authorization' = 'Bearer {0}' -f $env:SNOW_TOKEN } - } elseif ( $env:SNOW_USER -and $env:SNOW_PASS ) { + } + elseif ( $env:SNOW_USER -and $env:SNOW_PASS ) { $hashOut.Credential = New-Object System.Management.Automation.PSCredential($env:SNOW_USER, ($env:SNOW_PASS | ConvertTo-SecureString -AsPlainText -Force)) - } else { + } + else { throw 'A ServiceNow server environment variable has been set, but authentication via SNOW_TOKEN or SNOW_USER/SNOW_PASS was not found' } - } else { + } + else { throw "You must authenticate by either calling the New-ServiceNowSession cmdlet or passing in an Azure Automation connection object" } } From 2a10ac2a05fd63c3daa1995a6fd8b8dcfd078d26 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 24 Jul 2023 08:49:49 -0400 Subject: [PATCH 334/348] Release prep --- RELEASE.md | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 866c6b1..e51d45b 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,13 +1 @@ -- Add `Update-ServiceNowRecord -CustomVariableData` to update custom variable values, [#237](https://github.com/Snow-Shell/servicenow-powershell/issues/237) -- Add `New-ServiceNowChangeRequest` support for change models and standard change templates -- Fix 0 byte file error with `Add-ServiceNowAttachment`, [#241](https://github.com/Snow-Shell/servicenow-powershell/issues/241) -- `Get-ServiceNowRecord -New` has been deprecated and the new format is the only option -- `Update-ServiceNowChangeRequest`, `Update-ServiceNowincident`, and `Update-ServiceNowRequestedItem` deprecated. Use `Update-ServiceNowRecord`. The only difference was the table name and didn't make sense to maintain so many functions when documenting will do. `Update-ServiceNowRecord` has been enhanced as well so all updates can take advantage. -- `Get-ServiceNowRecordInterim` has been deprecated. -- Add generic `-Table` and `-ID` lookup function has been created and used across all functions where these parameters are used -- Add `-Table` tab ahead for `Remove-ServiceNowRecord` and `Export-ServiceNowRecord` -- Add `-ID` only lookup, no table name needed, for all -- Add/Update parameter sets to make it clearer when to use `-Table`, `-ID`, `-Filter`, etc -- Add pipeline support to `Export-ServiceNowRecord`, `New-ServiceNowRecord`, and `Update-ServiceNowRecord` -- Add `Get-ServiceNowRecord -ParentID` without providing `-Table` returns all tasks associated with that parent record -- Standardize parameter names across functions +- Add workaround for powershell basic header bug, [#249](https://github.com/Snow-Shell/servicenow-powershell/issues/249) From 5dbf605e1e0ef8fdab41903d2f4465b34ee70aba Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Mon, 24 Jul 2023 12:54:27 +0000 Subject: [PATCH 335/348] Update manifest to 4.0.1 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f69c1..ab27888 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.0.1 +- Add workaround for powershell basic header bug, [#249](https://github.com/Snow-Shell/servicenow-powershell/issues/249) + + ## 4.0.0 - Add `Update-ServiceNowRecord -CustomVariableData` to update custom variable values, [#237](https://github.com/Snow-Shell/servicenow-powershell/issues/237) - Add `New-ServiceNowChangeRequest` support for change models and standard change templates @@ -196,3 +200,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index e01a7f4..96dc083 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Greg Brownstein, Rick Arroues, Sam Martin # -# Generated on: 03/16/2023 +# Generated on: 07/24/2023 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '4.0.0' +ModuleVersion = '4.0.1' # Supported PSEditions # CompatiblePSEditions = @() From 5ce1df6b3740372e5cdfb9b4756334c184a15695 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 8 Nov 2023 15:30:02 -0500 Subject: [PATCH 336/348] Add instance timeout (#253) - add instance level timeout, `New-ServiceNowSession -TimeoutSec` --- ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 | 6 ------ ServiceNow/Public/New-ServiceNowSession.ps1 | 11 +++++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 1f8655e..5eba518 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -138,12 +138,6 @@ function Invoke-ServiceNowRestMethod { $params.Body = [System.Text.Encoding]::UTf8.GetBytes($Body) } - # if ( $Body ) { - # $params.Body = $Body - # } - - # Write-Verbose ($params | ConvertTo-Json) - # hide invoke-webrequest progress $oldProgressPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' diff --git a/ServiceNow/Public/New-ServiceNowSession.ps1 b/ServiceNow/Public/New-ServiceNowSession.ps1 index 002576a..20f5713 100644 --- a/ServiceNow/Public/New-ServiceNowSession.ps1 +++ b/ServiceNow/Public/New-ServiceNowSession.ps1 @@ -35,6 +35,10 @@ Use GraphQL instead of REST calls .PARAMETER GetAllTable Populate $ServiceNowTable with data from all tables the user has access to +.PARAMETER TimeoutSec +Timeout in seconds for all operations. +The default is 0 which represents no timeout. + .PARAMETER PassThru Provide the resulting session object to the pipeline as opposed to setting as a script scoped variable to be used by default for other calls. This is useful if you want to have multiple sessions with different api versions, credentials, etc. @@ -119,6 +123,10 @@ function New-ServiceNowSession { [Parameter()] [switch] $GraphQL, + [Parameter()] + [ValidateRange(0, [int32]::MaxValue)] + [int32] $TimeoutSec = 0, + [Parameter()] [switch] $PassThru ) @@ -148,6 +156,9 @@ function New-ServiceNowSession { } } + $script:PSDefaultParameterValues['Invoke-WebRequest:TimeoutSec'] = $TimeoutSec + $script:PSDefaultParameterValues['Invoke-RestMethodt:TimeoutSec'] = $TimeoutSec + switch -Wildcard ($PSCmdLet.ParameterSetName) { 'OAuth*' { $params = @{ From 05bc7b9920954045a823620c915fd736df9da74f Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 8 Nov 2023 15:31:33 -0500 Subject: [PATCH 337/348] Update RELEASE.md --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index e51d45b..7269f98 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1 +1 @@ -- Add workaround for powershell basic header bug, [#249](https://github.com/Snow-Shell/servicenow-powershell/issues/249) +- Add instance level timeout with `New-ServiceNowSession -TimeoutSec`, [#246](https://github.com/Snow-Shell/servicenow-powershell/issues/246) From 2971be14723f4b96e5bc79e23a72885c76c7228f Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Wed, 8 Nov 2023 20:32:11 +0000 Subject: [PATCH 338/348] Update manifest to 4.0.2 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab27888..6b335dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.0.2 +- Add instance level timeout with `New-ServiceNowSession -TimeoutSec`, [#246](https://github.com/Snow-Shell/servicenow-powershell/issues/246) + + ## 4.0.1 - Add workaround for powershell basic header bug, [#249](https://github.com/Snow-Shell/servicenow-powershell/issues/249) @@ -201,3 +205,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 96dc083..3b6efcc 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Greg Brownstein, Rick Arroues, Sam Martin # -# Generated on: 07/24/2023 +# Generated on: 11/08/2023 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '4.0.1' +ModuleVersion = '4.0.2' # Supported PSEditions # CompatiblePSEditions = @() From b9e890d77f2950ee7e1a2435e282b7c0d2d50890 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sun, 19 Nov 2023 09:57:07 -0500 Subject: [PATCH 339/348] Fix New-ServiceNowChangeTask not linking to parent (#256) --- ServiceNow/Public/New-ServiceNowChangeRequest.ps1 | 10 +++++----- ServiceNow/Public/New-ServiceNowChangeTask.ps1 | 11 ++++++----- ServiceNow/Public/New-ServiceNowIncident.ps1 | 12 ++++++------ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 index e8bf90b..98291b8 100644 --- a/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeRequest.ps1 @@ -35,7 +35,7 @@ .PARAMETER ConfigurationItem Full name or sys_id of the configuration item to be associated with the change -.PARAMETER InputData +.PARAMETER CustomField Field values which aren't one of the built in function properties .PARAMETER ServiceNowSession @@ -109,8 +109,8 @@ function New-ServiceNowChangeRequest { [string] $ConfigurationItem, [parameter()] - [Alias('CustomFields')] - [hashtable] $InputData, + [Alias('CustomFields', 'InputData')] + [hashtable] $CustomField, [Parameter()] [Hashtable] $Connection, @@ -141,12 +141,12 @@ function New-ServiceNowChangeRequest { } # add custom fields - $duplicateValues = ForEach ($Key in $InputData.Keys) { + $duplicateValues = ForEach ($Key in $CustomField.Keys) { If ( $values.ContainsKey($Key) ) { $Key } Else { - $values.Add($Key, $InputData[$Key]) + $values.Add($Key, $CustomField[$Key]) } } diff --git a/ServiceNow/Public/New-ServiceNowChangeTask.ps1 b/ServiceNow/Public/New-ServiceNowChangeTask.ps1 index a879cd5..b0cf9d6 100644 --- a/ServiceNow/Public/New-ServiceNowChangeTask.ps1 +++ b/ServiceNow/Public/New-ServiceNowChangeTask.ps1 @@ -31,7 +31,7 @@ function New-ServiceNowChangeTask { Return the newly created item details .EXAMPLE - New-ServiceNowChangeTask -ChangeRequest RITM0010001 -ShortDescription 'New PS change request' -Description 'This change request was created from Powershell' -AssignmentGroup ServiceDesk + New-ServiceNowChangeTask -ChangeRequest CHG0010001 -ShortDescription 'New PS change request' -Description 'This change request was created from Powershell' -AssignmentGroup ServiceDesk Create a new task @@ -82,6 +82,7 @@ function New-ServiceNowChangeTask { switch ($PSBoundParameters.Keys) { 'ChangeRequest' { $createValues.parent = $ChangeRequest + $createValues.change_request = $ChangeRequest } 'ShortDescription' { @@ -101,11 +102,11 @@ function New-ServiceNowChangeTask { } } - $CustomField.GetEnumerator() | ForEach-Object { - if ( $createValues.($_.Key) ) { - Write-Warning ('Custom field {0} has already been added via parameter' -f $_.Key) + foreach ($key in $CustomField.Keys) { + if ( $createValues.$key ) { + Write-Warning "Custom field '$key' has already been provided via one of the dedicated parameters" } else { - $createValues.Add($_.Key, $_.Value) + $createValues.Add($key, $CustomField.$key) } } diff --git a/ServiceNow/Public/New-ServiceNowIncident.ps1 b/ServiceNow/Public/New-ServiceNowIncident.ps1 index bd6e206..0b5e8bc 100644 --- a/ServiceNow/Public/New-ServiceNowIncident.ps1 +++ b/ServiceNow/Public/New-ServiceNowIncident.ps1 @@ -29,7 +29,7 @@ Generates a new ServiceNow Incident using predefined or other field values .PARAMETER ConfigurationItem Full name or sys_id of the configuration item to be associated with the change -.PARAMETER InputData +.PARAMETER CustomField Field values which aren't one of the built in function properties .PARAMETER ServiceNowSession @@ -56,7 +56,7 @@ Generate a basic Incident attributed to the caller "UserName" with descriptions, Category = "Office" Subcategory = "Outlook" ConfigurationItem = "UserPC1" - InputData = @{u_custom1 = "Custom Field Entry" + CustomField = @{u_custom1 = "Custom Field Entry" u_another_custom = "Related Test"} } New-ServiceNowIncident @IncidentParams @@ -93,8 +93,8 @@ function New-ServiceNowIncident { [string] $ConfigurationItem, [parameter()] - [Alias('CustomFields')] - [hashtable] $InputData, + [Alias('CustomFields', 'InputData')] + [hashtable] $CustomField, [Parameter()] [Hashtable] $Connection, @@ -124,12 +124,12 @@ function New-ServiceNowIncident { } # add custom fields - $duplicateValues = ForEach ($Key in $InputData.Keys) { + $duplicateValues = ForEach ($Key in $CustomField.Keys) { If ( $values.ContainsKey($Key) ) { $Key } Else { - $values.Add($Key, $InputData[$Key]) + $values.Add($Key, $CustomField[$Key]) } } From e38eaea43d41fa33249ce67bbc49fd52a518bf93 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Sun, 19 Nov 2023 14:57:58 +0000 Subject: [PATCH 340/348] Update manifest to 4.0.3 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b335dd..ff1ca98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.0.3 +- Add instance level timeout with `New-ServiceNowSession -TimeoutSec`, [#246](https://github.com/Snow-Shell/servicenow-powershell/issues/246) + + ## 4.0.2 - Add instance level timeout with `New-ServiceNowSession -TimeoutSec`, [#246](https://github.com/Snow-Shell/servicenow-powershell/issues/246) @@ -206,3 +210,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 3b6efcc..f383bd7 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Greg Brownstein, Rick Arroues, Sam Martin # -# Generated on: 11/08/2023 +# Generated on: 11/19/2023 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '4.0.2' +ModuleVersion = '4.0.3' # Supported PSEditions # CompatiblePSEditions = @() From 730ae649d26f402fa533d252a2fb091da2a62de6 Mon Sep 17 00:00:00 2001 From: Dave Hope Date: Thu, 11 Jul 2024 19:53:02 +0100 Subject: [PATCH 341/348] Pass string array to ParseExact to increase success chance (#266) Passing a string[] to ParseExact means that an exception is less likely to be thrown. --- ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 5eba518..1cd6244 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -249,19 +249,12 @@ function Invoke-ServiceNowRestMethod { $CultureDateTimeFormat = (Get-Culture).DateTimeFormat $DateFormat = $CultureDateTimeFormat.ShortDatePattern $TimeFormat = $CultureDateTimeFormat.LongTimePattern - $DateTimeFormat = "$DateFormat $TimeFormat" + $DateTimeFormat = [string[]]@("$DateFormat $TimeFormat", 'yyyy-MM-dd HH:mm:ss') $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) } Catch { - Try { - # Universal Format - $DateTimeFormat = 'yyyy-MM-dd HH:mm:ss' - $SNResult.$Property = [DateTime]::ParseExact($($SNResult.$Property), $DateTimeFormat, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None) - } - Catch { - # If the local culture and universal formats both fail keep the property as a string (Do nothing) - $null = 'Silencing a PSSA alert with this line' - } + # If the local culture and universal formats both fail keep the property as a string (Do nothing) + $null = 'Silencing a PSSA alert with this line' } } } From 4ca49f712c7816a3702b225be18dd4a325a5f8f7 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 12 Jul 2024 08:06:09 -0400 Subject: [PATCH 342/348] convert arrays to comma sep string (#261) --- ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 | 2 +- ServiceNow/Public/Update-ServiceNowRecord.ps1 | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 1cd6244..5408347 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -130,7 +130,7 @@ function Invoke-ServiceNowRestMethod { } if ( $Values ) { - $Body = $Values | ConvertTo-Json + $Body = $Values | ConvertTo-Json -Compress $params.Body = $Body Write-Verbose ($params | ConvertTo-Json) diff --git a/ServiceNow/Public/Update-ServiceNowRecord.ps1 b/ServiceNow/Public/Update-ServiceNowRecord.ps1 index c1a2ca8..5d3b78d 100644 --- a/ServiceNow/Public/Update-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Update-ServiceNowRecord.ps1 @@ -105,6 +105,13 @@ function Update-ServiceNowRecord { if ( $PSBoundParameters.ContainsKey('InputData') ) { + # arrays should be passed as comma-separated + foreach ($key in @($InputData.Keys)) { + if ( $InputData[$key].GetType().IsArray ) { + $InputData[$key] = $InputData[$key] -join ',' + } + } + $params = @{ Method = 'Patch' Table = $thisTable.Name From 84f3308944fd51a73dcae6c9c05c5f6f49c4b391 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 12 Jul 2024 08:09:04 -0400 Subject: [PATCH 343/348] support filter string from ui (#268) --- .../Private/Invoke-ServiceNowRestMethod.ps1 | 12 +++++++++-- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 20 ++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 index 5408347..9345968 100644 --- a/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 +++ b/ServiceNow/Private/Invoke-ServiceNowRestMethod.ps1 @@ -45,6 +45,9 @@ function Invoke-ServiceNowRestMethod { [parameter()] [object[]] $Filter, + [parameter()] + [string] $FilterString, + [parameter()] [object[]] $Sort = @('opened_at', 'desc'), @@ -98,10 +101,15 @@ function Invoke-ServiceNowRestMethod { if ( $Method -eq 'Get') { $Body = @{ 'sysparm_display_value' = $DisplayValue - 'sysparm_query' = (New-ServiceNowQuery -Filter $Filter -Sort $Sort) 'sysparm_limit' = 10 } + if ( $FilterString ) { + $Body.sysparm_query = $FilterString + } else { + $Body.sysparm_query = (New-ServiceNowQuery -Filter $Filter -Sort $Sort) + } + # Handle paging parameters # The value of -First defaults to [uint64]::MaxValue if not specified. # If no paging information was provided, default to the legacy behavior, which was to return 10 records. @@ -275,4 +283,4 @@ function Invoke-ServiceNowRestMethod { } $records -} +} \ No newline at end of file diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 5441853..8259f4d 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -33,6 +33,10 @@ For a complete list of comparison operators, see $script:ServiceNowOperator and use Name in your filter. See the examples. + .PARAMETER FilterString + A string representation of the filter. This is useful when the filter is complex and hard to specify as an array. + Retrieve the filter string from the ServiceNow UI via right click on the filter and selecting 'Copy query'. + .PARAMETER Sort Array or multidimensional array of fields to sort on. Each array should be of the format @(field, asc/desc). @@ -143,6 +147,11 @@ Get a specific record by number using the function alias + .EXAMPLE + Get-ServiceNowRecord -Table 'incident' -FilterString 'active=true^state=1' + + Provide a filter string from the UI to get records where active is true and state is 1 + .INPUTS ID @@ -165,6 +174,7 @@ function Get-ServiceNowRecord { [Parameter(ParameterSetName = 'Table', Mandatory)] [Parameter(ParameterSetName = 'TableId', Mandatory)] [Parameter(ParameterSetName = 'TableParentId')] + [Parameter(ParameterSetName = 'FilterString', Mandatory)] [Alias('sys_class_name')] [string] $Table, @@ -204,6 +214,10 @@ function Get-ServiceNowRecord { [Parameter(ParameterSetName = 'TableParentId')] [object[]] $Filter = @(), + [Parameter(ParameterSetName = 'FilterString', Mandatory)] + [Alias('fs')] + [string] $FilterString, + [Parameter(ParameterSetName = 'Table')] [Parameter(ParameterSetName = 'TableParentId')] [ValidateNotNullOrEmpty()] @@ -234,7 +248,6 @@ function Get-ServiceNowRecord { process { $thisParams = @{ - Filter = $Filter Property = $Property Sort = $Sort DisplayValue = $DisplayValue @@ -246,6 +259,7 @@ function Get-ServiceNowRecord { } if ( $PSBoundParameters.ContainsKey('Filter') ) { + $thisParams.Filter = $Filter # # we always want the filter to be arrays separated by joins if ( $Filter[0].GetType().Name -ne 'Object[]' ) { # @@ -253,6 +267,10 @@ function Get-ServiceNowRecord { } } + if ( $FilterString ) { + $thisParams.FilterString = $FilterString + } + $addedSysIdProp = $false # we need the sys_id value in order to get custom var data # add it in if specific properties were requested and not part of the list From 0179707386acf43778260d3f9984c44f1f0a2b7c Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 12 Jul 2024 09:04:26 -0400 Subject: [PATCH 344/348] release prep --- RELEASE.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 7269f98..b0b6ff0 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1 +1,3 @@ -- Add instance level timeout with `New-ServiceNowSession -TimeoutSec`, [#246](https://github.com/Snow-Shell/servicenow-powershell/issues/246) +- Add `Get-ServiceNowRecord -FilterString` to provide a filter from the UI, [#267](https://github.com/Snow-Shell/servicenow-powershell/issues/267) +- Update datetime conversion in `Get-ServiceNowRecord` to reduce possible exceptions, [#265](https://github.com/Snow-Shell/servicenow-powershell/issues/265) +- Fix list based fields appending brackets in `Update-ServiceNowRecord`, [#260](https://github.com/Snow-Shell/servicenow-powershell/issues/260) From f67829a6e2670d61bb6b3bc3213d4d270d4da008 Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 12 Jul 2024 13:15:16 +0000 Subject: [PATCH 345/348] Update manifest to 4.0.4 --- CHANGELOG.md | 7 +++++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff1ca98..ca8fbab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 4.0.4 +- Add `Get-ServiceNowRecord -FilterString` to provide a filter from the UI, [#267](https://github.com/Snow-Shell/servicenow-powershell/issues/267) +- Update datetime conversion in `Get-ServiceNowRecord` to reduce possible exceptions, [#265](https://github.com/Snow-Shell/servicenow-powershell/issues/265) +- Fix list based fields appending brackets in `Update-ServiceNowRecord`, [#260](https://github.com/Snow-Shell/servicenow-powershell/issues/260) + + ## 4.0.3 - Add instance level timeout with `New-ServiceNowSession -TimeoutSec`, [#246](https://github.com/Snow-Shell/servicenow-powershell/issues/246) @@ -211,3 +217,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index f383bd7..21da2cf 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Greg Brownstein, Rick Arroues, Sam Martin # -# Generated on: 11/19/2023 +# Generated on: 07/12/2024 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '4.0.3' +ModuleVersion = '4.0.4' # Supported PSEditions # CompatiblePSEditions = @() From e500b2dbd978ab0612ef0b93112ca2128ca8ad86 Mon Sep 17 00:00:00 2001 From: CATgwalker <78571293+CATgwalker@users.noreply.github.com> Date: Sat, 13 Jul 2024 07:14:51 -0500 Subject: [PATCH 346/348] Update Get-ServiceNowRecord.ps1 (#263) * Update Get-ServiceNowRecord.ps1 Fixes error "Id must either be a SysId 32 character alphanumeric or Number with prefix and id." and retains ID from reference table for further lookup. * Update Get-ServiceNowRecord.ps1 Additional fixes for reference table lookup where value is not in the 32 character format expected by SNOW. * Update ServiceNow/Public/Get-ServiceNowRecord.ps1 Co-authored-by: Greg Brownstein --------- Co-authored-by: Greg Brownstein --- ServiceNow/Public/Get-ServiceNowRecord.ps1 | 49 ++++++++++++---------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/ServiceNow/Public/Get-ServiceNowRecord.ps1 b/ServiceNow/Public/Get-ServiceNowRecord.ps1 index 8259f4d..62b7a54 100644 --- a/ServiceNow/Public/Get-ServiceNowRecord.ps1 +++ b/ServiceNow/Public/Get-ServiceNowRecord.ps1 @@ -183,8 +183,7 @@ function Get-ServiceNowRecord { [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true - } - else { + } else { throw 'Id must either be a SysId 32 character alphanumeric or Number with prefix and id.' } })] @@ -195,8 +194,7 @@ function Get-ServiceNowRecord { [ValidateScript( { if ($_ -match '^[a-zA-Z0-9]{32}$' -or $_ -match '^([a-zA-Z]+)[0-9]+$') { $true - } - else { + } else { throw 'ParentId must either be a SysId 32 character alphanumeric or Number with prefix and id.' } })] @@ -287,8 +285,7 @@ function Get-ServiceNowRecord { if ( $thisID -match '^[a-zA-Z0-9]{32}$' ) { $thisParams.Filter += , @('sys_id', '-eq', $thisID) - } - else { + } else { $thisParams.Filter += , @('number', '-eq', $thisID) } } @@ -301,8 +298,7 @@ function Get-ServiceNowRecord { if ( $ParentID -match '^[a-zA-Z0-9]{32}$' ) { $thisParams.Filter += , @('parent.sys_id', '-eq', $ParentID) - } - else { + } else { $thisParams.Filter += , @('parent.number', '-eq', $ParentID) } @@ -381,43 +377,50 @@ function Get-ServiceNowRecord { # show the underlying value if the option is a reference type if ( $newVar.Type -eq 'Reference' ) { - $newVar | Add-Member @{'ReferenceTable' = $var.'sc_item_option.item_option_new.reference' } - # issue 234. ID might not be sysid or number for reference...odd - $refValue = Get-ServiceNowRecord -Table $var.'sc_item_option.item_option_new.reference' -ID $var.'sc_item_option.value' -Property name -AsValue -ServiceNowSession $ServiceNowSession -ErrorAction SilentlyContinue - if ( $refValue ) { - $newVar.Value = $refValue + #do not do any further lookup when the value is blank or null + #resolves #234 and 262 + if ($var.'sc_item_option.value' -eq "" -or $null -eq $var.'sc_item_option.value') { + continue } + $sysidPattern = "[0-9a-fA-F]{32}" + $sysid = [Regex]::Matches($var.'sc_item_option.value', $sysidPattern).Value + if ($sysid) { + Write-Verbose "Custom variable lookup for $($newvar.name) from table '$($var.'sc_item_option.item_option_new.reference')' sysid:'$($var.'sc_item_option.value')'" + $newVar | Add-Member @{'ReferenceTable' = $var.'sc_item_option.item_option_new.reference' } + $newVar | Add-Member @{'ReferenceID' = $var.'sc_item_option.value' } + # issue 234. ID might not be sysid or number for reference...odd + $refValue = Get-ServiceNowRecord -Table $var.'sc_item_option.item_option_new.reference' -ID $var.'sc_item_option.value' -Property name -AsValue -ServiceNowSession $ServiceNowSession -ErrorAction SilentlyContinue + if ( $refValue ) { + $newVar.Value = $refValue + } + } + } if ( $var.'sc_item_option.item_option_new.name' ) { $record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.name' = $newVar } - } - else { + } else { $record.CustomVariable | Add-Member @{ $var.'sc_item_option.item_option_new.question_text' = $newVar } } } if ( $addedSysIdProp ) { $record | Select-Object -Property * -ExcludeProperty sys_id - } - else { + } else { $record } } - } - else { + } else { # format the results if ( $Property ) { if ( $Property.Count -eq 1 -and $AsValue ) { $propName = $result | Get-Member | Where-Object { $_.MemberType -eq 'NoteProperty' } | Select-Object -ExpandProperty Name $result.$propName - } - else { + } else { $result } - } - else { + } else { if ($thisTable.Type) { $result | ForEach-Object { $_.PSObject.TypeNames.Insert(0, $thisTable.Type) } } From 6b8ac10f85a8a8081b12cd5c7c6a68c88239018b Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 30 Aug 2024 17:56:10 -0400 Subject: [PATCH 347/348] release prep --- RELEASE.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index b0b6ff0..a39ba9e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,3 +1 @@ -- Add `Get-ServiceNowRecord -FilterString` to provide a filter from the UI, [#267](https://github.com/Snow-Shell/servicenow-powershell/issues/267) -- Update datetime conversion in `Get-ServiceNowRecord` to reduce possible exceptions, [#265](https://github.com/Snow-Shell/servicenow-powershell/issues/265) -- Fix list based fields appending brackets in `Update-ServiceNowRecord`, [#260](https://github.com/Snow-Shell/servicenow-powershell/issues/260) +- Fix invalid Id error, [#262](https://github.com/Snow-Shell/servicenow-powershell/issues/262) From 6280337ab6cb53c59f9443b00240d32e8001bc7c Mon Sep 17 00:00:00 2001 From: Greg Brownstein Date: Fri, 30 Aug 2024 21:56:44 +0000 Subject: [PATCH 348/348] Update manifest to 4.0.5 --- CHANGELOG.md | 5 +++++ ServiceNow/ServiceNow.psd1 | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca8fbab..f2b5a1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 4.0.5 +- Fix invalid Id error, [#262](https://github.com/Snow-Shell/servicenow-powershell/issues/262) + + ## 4.0.4 - Add `Get-ServiceNowRecord -FilterString` to provide a filter from the UI, [#267](https://github.com/Snow-Shell/servicenow-powershell/issues/267) - Update datetime conversion in `Get-ServiceNowRecord` to reduce possible exceptions, [#265](https://github.com/Snow-Shell/servicenow-powershell/issues/265) @@ -218,3 +222,4 @@ Be able to reference types from this config per table, removing the need to have + diff --git a/ServiceNow/ServiceNow.psd1 b/ServiceNow/ServiceNow.psd1 index 21da2cf..ba174d2 100644 --- a/ServiceNow/ServiceNow.psd1 +++ b/ServiceNow/ServiceNow.psd1 @@ -3,7 +3,7 @@ # # Generated by: Greg Brownstein, Rick Arroues, Sam Martin # -# Generated on: 07/12/2024 +# Generated on: 08/30/2024 # @{ @@ -12,7 +12,7 @@ RootModule = 'ServiceNow.psm1' # Version number of this module. -ModuleVersion = '4.0.4' +ModuleVersion = '4.0.5' # Supported PSEditions # CompatiblePSEditions = @()