lordmilko / PrtgAPI

C#/PowerShell interface for PRTG Network Monitor
MIT License
301 stars 37 forks source link

save session #173

Closed AlexN-github closed 3 years ago

AlexN-github commented 3 years ago

How can I save an existing session Get-PrtgClient and transfer it, for example, to Start-Job. Or is there another inline way to run the cmdlet asynchronously?

lordmilko commented 3 years ago

Hi @AlexN-github

The current PrtgClient is stored in the internal static member PrtgSessionState.Client. Since jobs run in a separate process, this field is no longer initialized. Therefore in order to run a PrtgAPI cmdlet asynchronously you simply need to re-initialize this field inside of the process the job is running in.

You can pass arguments to a job via the -ArgumentList parameter; however as these parameters are actually serialized to a custom type, the best strategy would likely be to simply use the data from the old PrtgClient to reconnect to PRTG inside of the job and then go from there

$client = Get-PrtgClient

Start-Job {
    param($client)

    Connect-PrtgServer $client.Server (New-Credential $client.UserName $client.PassHash) -PassHash -Force

    Get-Probe

} -ArgumentList $client | Wait-Job | Receive-Job
AlexN-github commented 3 years ago

Lordmilko, thanks for the quick response and the wonderful Powershell API for PRTG. We are very active in using your module to integrate various tasks with PRTG and create various automations. The command 'Connect-PrtgServer $ client.Server (New-Credential $ client.UserName $ client.PassHash) -PassHash -Force', as I understand it, will create a new session again. I would like to run a lot of such asynchronous requests and would not like to load the server with creating an authorization process and receiving a session. It would be very nice if, instead of creating a new session, you could transfer the session to an asynchronous process and use some command Set-PrtgClient there

lordmilko commented 3 years ago

Hi @AlexN-github,

The PRTG HTTP is a stateless, RESTful API. As such there is no "authorization process" or "session". When you normally connect using Connect-PrtgServer and specify a username and password, PrtgAPI will translate that password into a passhash to use for all future requests for greater security; once you have a passhash however you can endlessly keep creating new PrtgClient objects without generating any requests to the PRTG server. A PrtgClient is simply a handy wrapper around the credentials you provided. Even Set-PrtgClient will create a new PrtgClient object for you in some scenarios, as uniqueness of the object doesn't matter

AlexN-github commented 3 years ago

Strange, but getting a session variable like this helps me not to send credentials in every request. That is, the PRTG server issues a permanent session key. Invoke-WebRequest -uri "https: //hostname/Portal/api/public/testlogin.htm?Username=$UN&passhash=$PW" -UseBasicParsing -SessionVariable 'Session' And if I used only the PRTG API, then it would be enough for me to transfer only this session key to Start -Job

lordmilko commented 3 years ago

PrtgAPI uses the authentication system as described in the API documentation under /api.htm?tabid=2 on your PRTG server

All requests to the API are "stateless" which means that there is no multi-step login process of any kind. The authentication with username/passhash (or username/password) must always be included in each request by using the username and passhash (or username and password) parameters.

With these parameters the URLs will look like this: http://yourserver/api/table.xml?content=sensors&columns=sensor&username=myuser&passhash=hash or: http://yourserver/api/table.xml?content=sensors&columns=sensor&username=myuser&password=mypassword

You can request the password hash for an account with an API call: http://yourserver/api/getpasshash.htm?username=myuser&password=mypassword Note: Make sure that username and password are URL-encoded .

PRTG in your web browser uses testlogin and cookies and sessions and such; PrtgAPI does use cookies on rare occasions (such as creating sensors) however it obtains these cookies automatically from other API requests that are executed before the request requiring a cookie is executed.

AlexN-github commented 3 years ago

If I understand correctly, the Session variable stores the session key, which comes in response from the server and is then stored in cookies. $ Session.Cookies.GetCookies (https://hostname) Comment: CommentUri: HttpOnly: True Discard: False Domain: hostname Expired: False Expires: 01.01.0001 0:00:00 Name: OCTOPUS193523502 Path: / Port: Secure: False TimeStamp: 10/02/2020 11:19:50 AM Value: ezY5MEJEODhDLTc0OTMtNDlBQS05NEM3LURGMzA0NDU5MjQ1Nn0%3D Version: 0

It may be strange, but it works. Apparently I found something undocumented Paessler