Skip to content

Commit fbef90e

Browse files
authored
Merge pull request #220 from snazy2000/develop
Release 1.10
2 parents 7022b9f + f4592ae commit fbef90e

File tree

160 files changed

+3678
-2011
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

160 files changed

+3678
-2011
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/),
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
# [v.1.10.x] - 2021-09-03
9+
10+
## New secure ways to connect Snipe it
11+
12+
### -secureApiKey allow pass apiKey as SecureString
13+
Connect-SnipeitPS -URL 'https://asset.example.com' -secureApiKey 'tokenKey'
14+
15+
### Set connection with safely saved credentials, first save credentials
16+
$SnipeCred= Get-Credential -message "Use url as username and apikey as password"
17+
$SnipeCred | Export-CliXml snipecred.xml
18+
19+
### ..then use your saved credentials like
20+
Connect-SnipeitPS -siteCred (Import-CliXml snipecred.xml)
21+
22+
## Fix for content encoding in invoke-snipeitmethod
23+
Version 1.9 introduced bug that converted non ascii characters to ascii
24+
during request.
25+
826
# [v.1.9.x] - 2021-07-14
927

1028
## Image uploads

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,23 @@ Install-Module SnipeitPS
1919
# Check for updates occasionally:
2020
Update-Module SnipeitPS
2121
22-
# To use each session:
22+
# import module to session:
2323
Import-Module SnipeitPS
24-
Set-SnipeitInfo -URL 'https://asset.example.com' -apiKey 'tokenKey'
24+
25+
# Set connection
26+
Connect-SnipeitPS -URL 'https://asset.example.com' -apiKey 'tokenKey'
27+
28+
# Or set connection with safely saved credentials, first save credentials
29+
$SnipeCred =Get-Credential -message "Use url as username and apikey as password"
30+
$SnipeCred | Export-CliXml snipecred.xml
31+
32+
# ..then use your saved credentials like
33+
Connect-SnipeitPS -siteCred (Import-CliXml snipecred.xml)
34+
35+
# OR use -secureApiKey that allow pass apiKey as SecureString
36+
# if you are usin Microsoft.PowerShell.SecretManagement or like
37+
Connect-SnipeitPS -URL 'https://asset.example.com' -secureApiKey 'tokenKey'
38+
2539
```
2640

2741
### Usage

SnipeitPS/Private/Invoke-SnipeitMethod.ps1

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,91 @@
1-
function Invoke-SnipeitMethod {
2-
<#
1+
<#
32
.SYNOPSIS
4-
Extracted invokation of the REST method to own function.
5-
#>
3+
Make api request to Snipe it
4+
5+
.PARAMETER Api
6+
Api part of url. prefix with slash ie. "/api/v1/hardware"
7+
8+
.PARAMETER Method
9+
Method of the invokation, one of following "GET", "POST", "PUT", "PATCH" or "DELETE"
10+
11+
.PARAMETER Body
12+
Request body as hashtable. Needed for post, put and patch
13+
14+
.PARAMETER GetParameters
15+
Get-Parameters as hastable.
16+
#>
17+
18+
function Invoke-SnipeitMethod {
619
[OutputType(
720
[PSObject]
821
)]
22+
923
param (
10-
# REST API to invoke
24+
1125
[Parameter(Mandatory = $true)]
12-
[Uri]$URi,
26+
[string]$Api,
1327

14-
# Method of the invokation
1528
[ValidateSet("GET", "POST", "PUT", "PATCH", "DELETE")]
1629
[string]$Method = "GET",
1730

18-
# Body of the request
1931
[Hashtable]$Body,
2032

21-
[string] $Token,
22-
23-
# GET Parameters
2433
[Hashtable]$GetParameters
25-
2634
)
2735

2836
BEGIN {
37+
#use legacy per command based url and apikey
38+
if ( $null -ne $SnipeitPSSession.legacyUrl -and $null -ne $SnipeitPSSession.legacyApiKey ) {
39+
[string]$Url = $SnipeitPSSession.legacyUrl
40+
Write-Debug "Invoke-SnipeitMethod url: $Url"
41+
$Token = ConvertFrom-SecureString -AsPlainText -SecureString $SnipeitPSSession.legacyApiKey
42+
43+
} elseif ($null -ne $SnipeitPSSession.url -and $null -ne $SnipeitPSSession.apiKey) {
44+
[string]$Url = $SnipeitPSSession.url
45+
Write-Debug "Invoke-SnipeitMethod url: $Url"
46+
$Token = ConvertFrom-SecureString -AsPlainText -SecureString $SnipeitPSSession.apiKey
47+
48+
} else {
49+
throw "Please use Connect-SnipeitPS to setup connection before any other commands."
50+
}
51+
2952
# Validation of parameters
3053
if (($Method -in ("POST", "PUT", "PATCH")) -and (!($Body))) {
3154
$message = "The following parameters are required when using the ${Method} parameter: Body."
3255
$exception = New-Object -TypeName System.ArgumentException -ArgumentList $message
3356
Throw $exception
3457
}
3558

59+
#Build request uri
60+
$apiUri = "$Url$Api"
3661
#To support images "image" property have be handled before this
3762

3863
$_headers = @{
39-
"Authorization" = "Bearer $($token)"
64+
"Authorization" = "Bearer $($Token)"
4065
'Content-Type' = 'application/json; charset=utf-8'
4166
"Accept" = "application/json"
4267
}
4368
}
4469

4570
Process {
46-
if ($GetParameters -and ($URi -notlike "*\?*"))
47-
{
71+
# This can be done using $Body, maybe some day - PetriAsi
72+
if ($GetParameters -and ($apiUri -notlike "*\?*")){
4873
Write-Debug "Using `$GetParameters: $($GetParameters | Out-String)"
49-
[string]$URI += (ConvertTo-GetParameter $GetParameters)
74+
[string]$apiUri = $apiUri + (ConvertTo-GetParameter $GetParameters)
5075
# Prevent recursive appends
5176
$GetParameters = $null
5277
}
5378

5479
# set mandatory parameters
5580
$splatParameters = @{
56-
Uri = $URi
81+
Uri = $apiUri
5782
Method = $Method
5883
Headers = $_headers
5984
UseBasicParsing = $true
6085
ErrorAction = 'SilentlyContinue'
6186
}
6287

63-
# Place holder for intended image manipulation
64-
# if and when snipe it API gets support for images
88+
# Send image requests as multipart/form-data if supported
6589
if($null -ne $body -and $Body.Keys -contains 'image' ){
6690
if($PSVersionTable.PSVersion -ge '7.0'){
6791
$Body['image'] = get-item $body['image']
@@ -71,15 +95,15 @@
7195
$splatParameters["Method"] = 'POST'
7296
$splatParameters["Form"] = $Body
7397
} else {
74-
# use base64 encoded images for powershell version < 7
75-
Add-Type -AssemblyName "System.Web"
76-
$mimetype = [System.Web.MimeMapping]::GetMimeMapping($body['image'])
77-
$Body['image'] = 'data:@'+$mimetype+';base64,'+[Convert]::ToBase64String([IO.File]::ReadAllBytes($Body['image']))
98+
# use base64 encoded images for powershell version < 7
99+
Add-Type -AssemblyName "System.Web"
100+
$mimetype = [System.Web.MimeMapping]::GetMimeMapping($body['image'])
101+
$Body['image'] = 'data:@'+$mimetype+';base64,'+[Convert]::ToBase64String([IO.File]::ReadAllBytes($Body['image']))
78102
}
79103
}
80104

81105
if ($Body -and $splatParameters.Keys -notcontains 'Form') {
82-
$splatParameters["Body"] = $Body | Convertto-Json
106+
$splatParameters["Body"] = [System.Text.Encoding]::UTF8.GetBytes(($Body | Convertto-Json))
83107
}
84108

85109
$script:PSDefaultParameterValues = $global:PSDefaultParameterValues
@@ -105,26 +129,24 @@
105129
if ($webResponse) {
106130
Write-Verbose $webResponse
107131

108-
# API returned a Content: lets work wit it
132+
# API returned a Content: lets work with it
109133
try{
110-
111134
if ($webResponse.status -eq "error") {
112-
Write-Verbose "[$($MyInvocation.MyCommand.Name)] An error response was received from; resolving"
135+
Write-Verbose "[$($MyInvocation.MyCommand.Name)] An error response was received ... resolving"
113136
# This could be handled nicely in an function such as:
114137
# ResolveError $response -WriteError
115138
Write-Error $($webResponse.messages | Out-String)
116-
}
117-
else {
139+
} else {
118140
#update operations return payload
119-
if ($webResponse.payload){
141+
if ($webResponse.payload) {
120142
$result = $webResponse.payload
121143
}
122144
#Search operations return rows
123145
elseif ($webResponse.rows) {
124146
$result = $webResponse.rows
125147
}
126148
#Remove operations returns status and message
127-
elseif ($webResponse.status -eq 'success'){
149+
elseif ($webResponse.status -eq 'success') {
128150
$result = $webResponse.payload
129151
}
130152
#Search and query result with no results
@@ -140,9 +162,6 @@
140162
Write-Verbose "Messages: $($webResponse.messages)"
141163

142164
$result
143-
144-
145-
146165
}
147166
}
148167
catch {
@@ -151,7 +170,7 @@
151170

152171
}
153172
elseif ($webResponse.StatusCode -eq "Unauthorized") {
154-
Write-Error "[$($MyInvocation.MyCommand.Name)] You are not Authorized to access the resource, check your token is correct"
173+
Write-Error "[$($MyInvocation.MyCommand.Name)] You are not Authorized to access the resource, check your apiKey is correct"
155174
}
156175
else {
157176
# No content, although statusCode < 400
@@ -169,3 +188,4 @@
169188
Write-Verbose "[$($MyInvocation.MyCommand.Name)] Function ended"
170189
}
171190
}
191+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function Reset-SnipeitPSLegacyApi {
2+
[CmdletBinding(
3+
SupportsShouldProcess = $true,
4+
ConfirmImpact = "Low"
5+
)]
6+
param(
7+
)
8+
process {
9+
Write-Verbose 'Reset-SnipeitPSLegacyApi'
10+
if ($PSCmdlet.ShouldProcess("ShouldProcess?")) {
11+
$SnipeitPSSession.legacyUrl = $null
12+
$SnipeitPSSession.legacyApiKey = $null
13+
14+
}
15+
}
16+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function Set-SnipeitPSLegacyApiKey {
2+
[CmdletBinding(
3+
SupportsShouldProcess = $true,
4+
ConfirmImpact = "Low"
5+
)]
6+
param(
7+
[string]$apiKey
8+
)
9+
process {
10+
if ($PSCmdlet.ShouldProcess("ShouldProcess?")) {
11+
$SnipeitPSSession.legacyApiKey = ConvertTo-SecureString -AsPlainText -String $apiKey
12+
}
13+
}
14+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function Set-SnipeitPSLegacyUrl {
2+
[CmdletBinding(
3+
SupportsShouldProcess = $true,
4+
ConfirmImpact = "Low"
5+
)]
6+
param(
7+
$url
8+
)
9+
process {
10+
if ($PSCmdlet.ShouldProcess("ShouldProcess?")) {
11+
$SnipeitPSSession.legacyUrl = $url.TrimEnd('/')
12+
}
13+
}
14+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
function Test-SnipeitPSConnection {
2+
#test api connection
3+
$Parameters = @{
4+
Api = '/api/v1/statuslabels'
5+
Method = 'Get'
6+
GetParameters = @{'limit'=1}
7+
}
8+
Write-Verbose "Testing connection to $($SnipeitPSSession.url)."
9+
10+
$contest = Invoke-SnipeitMethod @Parameters
11+
12+
if ( $contest) {
13+
Write-Verbose "Connection to $($SnipeitPSSession.url) tested succesfully."
14+
return $true
15+
} else {
16+
return $false
17+
}
18+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<#
2+
.SYNOPSIS
3+
Sets authetication information
4+
5+
.DESCRIPTION
6+
Sets apikey and url to connect Snipe-It system.
7+
Based on Set-SnipeitInfo command, what is now just compatibility wrapper
8+
and calls Connect-SnipeitPS
9+
10+
.PARAMETER url
11+
URL of Snipeit system.
12+
13+
.PARAMETER apiKey
14+
User's API Key for Snipeit.
15+
16+
.PARAMETER secureApiKey
17+
Snipe it Api key as securestring
18+
19+
.PARAMETER siteCred
20+
PSCredential where username shoul be snipe it url and password should be
21+
snipe it apikey.
22+
23+
.EXAMPLE
24+
Connect-SnipeitPS -Url $url -apiKey $myapikey
25+
Connect to Snipe it api.
26+
27+
.EXAMPLE
28+
Connect-SnipeitPS -Url $url -SecureApiKey $myapikey
29+
Connects to Snipe it api with apikey stored to securestring
30+
31+
.EXAMPLE
32+
Connect-SnipeitPS -siteCred (Get-Credential -message "Use site url as username and apikey as password")
33+
Connect to Snipe It with PSCredential object.
34+
To use saved creadentials yu can use export-clixml and import-clixml commandlets.
35+
36+
.EXAMPLE
37+
Build credential with apikey value from secret vault (Microsoft.PowerShell.SecretManagement)
38+
$siteurl = "https://mysnipeitsite.url"
39+
$apikey = Get-SecretInfo -Name SnipeItApiKey
40+
$siteCred = New-Object -Type PSCredential -Argumentlist $siteurl,$spikey
41+
Connect-SnipeitPS -siteCred $siteCred
42+
43+
44+
45+
#>
46+
function Connect-SnipeitPS {
47+
[CmdletBinding(
48+
DefaultParameterSetName = 'Connect with url and apikey'
49+
)]
50+
[System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseShouldProcessForStateChangingFunctions', '')]
51+
52+
param (
53+
[Parameter(ParameterSetName='Connect with url and apikey',Mandatory=$true)]
54+
[Parameter(ParameterSetName='Connect with url and secure apikey',Mandatory=$true)]
55+
[Uri]$url,
56+
57+
[Parameter(ParameterSetName='Connect with url and apikey',Mandatory=$true)]
58+
[String]$apiKey,
59+
60+
[Parameter(ParameterSetName='Connect with url and secure apikey',Mandatory=$true)]
61+
[SecureString]$secureApiKey,
62+
63+
[Parameter(ParameterSetName='Connect with credential',Mandatory=$true)]
64+
[PSCredential]$siteCred
65+
)
66+
67+
68+
PROCESS {
69+
switch ($PsCmdlet.ParameterSetName) {
70+
'Connect with url and apikey' {
71+
$SnipeitPSSession.url = $url.AbsoluteUri.TrimEnd('/')
72+
$SnipeitPSSession.apiKey = ConvertTo-SecureString -AsPlainText -String $apiKey
73+
}
74+
75+
'Connect with url and secure apikey' {
76+
$SnipeitPSSession.url = $url.AbsoluteUri.TrimEnd('/')
77+
$SnipeitPSSession.apiKey = $secureApiKey
78+
}
79+
80+
'Connect with credential' {
81+
$SnipeitPSSession.url = ($siteCred.GetNetworkCredential().UserName).TrimEnd('/')
82+
$SnipeitPSSession.apiKey = $siteCred.GetNetworkCredential().SecurePassword
83+
}
84+
}
85+
86+
Write-Debug "Site-url $($SnipeitPSSession.url)"
87+
Write-Debug "Site apikey: $($SnipeitPSSession.apiKey)"
88+
89+
if (-not (Test-SnipeitPSConnection)) {
90+
throw "Cannot verify connection to snipe it. For the start try to check url and provided apikey or credential parameters"
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)