SnipeitPS icon indicating copy to clipboard operation
SnipeitPS copied to clipboard

Set-SnipeitInfo and others -url parameter

Open PetriAsi opened this issue 4 years ago • 9 comments
trafficstars

Context

To support all snipe it api features there's url-properties for supplier and manufacturer

Expected Behavior

It should be possible to use -url parameter to set items url property

Possible Solution

Rename SnipeitPS -url parameter to -ApiUrl and set parameter alias for Set-SnipeitInfo. Individual functions will be broken as it's not possible to to set alias. Or use some prefix for suppliers and manufactures. that would not break anything, just some consistency.

PetriAsi avatar Jul 09 '21 12:07 PetriAsi

I think its to big of a change to make as will break everyones scripts, I would just call it something different for suppliers and manufacturers maybe.

snazy2000 avatar Jul 21 '21 10:07 snazy2000

I'm not doing anything for this currently, just wrote some thoughts and created this issue.

As you suggested, prefixing parameters is safe way to go. It still generate some issues when prefixed url parameter is passed to Invoke-SnipeitRequest. Prefix have to be removed before request can be sent to snipe it. Removing prefix in Invoke-SnipeitRequest is doable, but not so clean way to solve this.

When I wrote this issue , I was thinking that aliasing "-ApiUrl" to "-url" would keep compatibility in most of cases. But change on other commands that are using -url parameters directly will broke.

I personally would prefer connect based approach, where every command doesn't have its own url and apikey parameters. Similar like many other modules are doing. First just do connect-snipeitps (or something like that ) and sub commands can be used after that. Combining that with storing url and apikey as credential to file, we could have scripts without any sensitive information. That can be done without breaking those who are currently using Set-SnipeitInfo, that can be set as alias to new connect command.

PetriAsi avatar Jul 24 '21 09:07 PetriAsi

@PetriAsi Setting up a connect is my preferred approach. One way we've been doing this at work is to use Microsoft.PowerShell.SecretManagement to store the API keys securely.

sheppyh avatar Jul 27 '21 09:07 sheppyh

Thanks @sheppyh ,Microsoft.PowerShell.SecretManagement looks interesting . I haven't used it before. It seem varyuseful for this.

I have been thinking way to do this without breaking existing scripts. Following could be one possible way to implement this.

  1. Make new way to connect to snipe-it: Connect-SnipeitPS command that
  • stores urls and apikeys using site url as key and apikey as value.
  • store last used site url Syntax would be something like:
#Setup new connection
Connect-SnipeitPS -site [url] -apikey [apikey]
#connect exiting selected site
Connect-SnipeitPS -site [url]
#connect last used site just without any parameters
Connect-SnipeitPS

Connect-SnipeitPS will use Set-DefaultParameter and set url and apikey for Invoke-SnipeItMethod. That way we can keep compatibility with existing commands.

  1. Make existing code to use new connect command and give warning if old syntax is used Change Set-SnipeitInfo to:
  • Call Connect-SnipeitPS to make connection
  • Give warning that Connect-SnipeitPS should be used instead All existing commands will still work as they did:
  • Drop mandatory flag from -url and -apikey
  • just give warning if url and apikey parameters are used, parameters are still passed to Invoke-SnipeMethod
  1. After couple releases of SnipePS to gallery, we could drop support for -url and -apikey parameters

How does it look, did I miss something?

PetriAsi avatar Jul 30 '21 19:07 PetriAsi

@sheppyh I looked closer SecretStore and couple of things came up. currently it does not allow multiple instances of secretstore so that SnipePS could create it's own store. Also automatically setting up SecretStore without password seems impossible. So it seem that SnipeitPS need something else.

I have used Configuration module to store credentials and other settings. In windows environment it's safe cause pscredential object are encrypted when saved. On other platforms, where configuration are saved in users home directory and only file permission protects it, but content is not human readable kind of encryption but not so strong.

Right now I'm planning to go with Configuration or coding SnipeitPS include simplier version of it's features. Maybe just creating config hastable and using export-clixml / import-clixml could do the trick.

PetriAsi avatar Jul 31 '21 08:07 PetriAsi

@PetriAsi Great investigation. I agree with your findings. I've also recently noticed that Configuration module does secure credential storage, would probably have been easier for us to use this from the start.

For SecretStore, we created an Initialize-SecretStore script which sets up the store without password. It does need to be run interactively though:

function Initialize-SecretStore {
    [CmdletBinding()]
    param (
    )

    process {
        # Install required modules
        $RequiredModules = "Microsoft.PowerShell.SecretManagement", "Microsoft.PowerShell.SecretStore"
        $RequiredModules | Foreach-Object {
            if (-not (Get-Command -Module $_)) {
                Write-Verbose "Module $_ not installed. Installing now..."
                Install-Module $_ -Scope AllUsers -Force
            }
        }

        # Register vault
        if (-not (Get-SecretVault | Where-Object ModuleName -eq "Microsoft.PowerShell.SecretStore")) {
            Write-Verbose "Registering secret vault"
            Register-SecretVault -ModuleName Microsoft.PowerShell.SecretStore
        }

        Write-Verbose "Disabling password requirement"
        Write-Warning "Please enter any temporary password during the next steps - it will not be used"

        Reset-SecretStore -Force
        Set-SecretStoreConfiguration -Authentication None -Interaction None
    }
}

We have a company PS profile which checks whether various credentials in the secret store exist (we only use one instance of the secret store), along with simple functions to set the credentials.

function Set-SnipeItApiKey {
    $Credential = Read-Host -AsSecureString
    Set-Secret SnipeItApiKey -Secret $Credential
}

function Disable-CredentialWarning {
    Set-Secret DisableCredentialWarning -Secret "true"
}

if(-not (Get-SecretInfo DisableCredentialWarning)) {
    if (-not (Get-SecretInfo -Name SnipeItApiKey)) {
        Write-Warning   '[Corporate PSProfile] SnipeIt API key not set, unable to access asset register. Use Set-SnipeItApiKey.'
        $GiveCredentialInfo = $true
    }
    if($GiveCredentialInfo) {
        Write-Warning   '[Corporate PSProfile] To suppres missing credential warnings, use: Disable-CredentialWarning'
        $GiveCredentialInfo = $false
    }
}

# SnipeItPS
if(Get-SecretInfo -Name SnipeItApiKey) {
    Set-Info -url "https://assets" -apiKey (Get-Secret -Name SnipeItApiKey -AsPlainText)
}

This way, any new users are prompted when opening PS for the first time to setup credentials. Then each time PS is run, the Set-SnipeitInfo command is run to set the SnipeIT credentials within the module's method to do this.

Anyway, above is just for info, I'm keen to use Configuration for a few modules at work also and think it would fit best here, especially as SecretStore changes a lot in development at the moment.

sheppyh avatar Aug 09 '21 15:08 sheppyh

@sheppyh Thank's for code sniplets.

I have already wrote some concept code for new Connect-SnipeitPS that allows easily depreciate -url and -apiKey parameters. New code is storing Set-SnipeitInfo url and apiKey to script scoped variables. Configuration module integration and multiple site support is still missing.

I'm still uncertain about basic concept, saving sites is nice, but at same time adds some complexity and same time restricts how authentication data is stored . Most of users needs only one site. I also expect those who care about security like if they can choose flexible ways to store credentials.

Something between current SnipeitPS and and saved sites method could be just simply accept PSCredential object for connection . Username can be used for site url and password is stored apiKey.

So writing new Connect-SnipeitPS to accept -url and -apiKey as currently and new alternative way with only -siteCred [PSCredential] would allow more flexibility as:

#Old school 
Connect-SnipeitPS -url  $url -apiKey $apiKey

#To prompt credentials
Connect-SnipeitPS -siteCred (Get-Credential -message "Use site url as username and apikey as password")

#Read exported PSCred from file
Connect-SnipeitPS -siteCred (Import-CliXml mysite.xml)

#Build credential from secret vault
$siteurl = "https://dasdjhjdsa.plaah"
$apikey = Get-SecretInfo -Name SnipeItApiKey
$siteCred = New-Object -Type PSCredential -Argumentlist $siteurl,$spikey
Connect-SnipeitPS -siteCred $siteCred

I was planning to store siteCred also to script scoped variable and use it in Invoke-SnipeitMethod and decrypt password just in time for every call.

This simple approach will be more flexible, no added module dependencies and it easily adopted to any platform.

PetriAsi avatar Aug 13 '21 09:08 PetriAsi

Merged #216 to develop. -url and -apiKey parameter will stay until 2.0 release, then it's time to clean up all legacy compatibility code.

PetriAsi avatar Aug 23 '21 20:08 PetriAsi

Released v.1.10 with new Connect-SnipeitPS command. Keeping this open as -url parameters are still used.

PetriAsi avatar Sep 03 '21 13:09 PetriAsi