Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 283fd7a703 | |||
| 3f6a59abad | |||
| 7b9d229289 | |||
| bc86ad2965 | |||
| f56784f2aa | |||
| 694822f0d6 | |||
| df30851a3a | |||
| 88e4e12e3d | |||
| 6541cf18c0 | |||
| 0b237c6d1c | |||
| 40e3c31c6f | |||
| 114267b1d5 | |||
| 010cce0fd8 | |||
| f8f240e313 | |||
| 7f856b1d09 | |||
| 31b56c75e1 | |||
| 7f0d14fc25 | |||
| 00975bb1c5 | |||
| fb39efd493 | |||
| e45d2665fa | |||
| 2af591dbbf | |||
| 85e13dc150 | |||
| d1128997cc | |||
| bc645fc0d8 | |||
| ced1dde708 | |||
| bad183aff4 | |||
| e456d7affe | |||
|
|
4c128f5864 | ||
|
|
0913fc2069 | ||
| ea9b760933 | |||
| 833bb183eb | |||
| ed9d648074 | |||
| ad9744bf56 | |||
| 1291bc0b69 | |||
| b1c5feb73b | |||
| 6fb2e81142 | |||
| 9912656752 | |||
| 538d84305f | |||
| 078beb8d3c | |||
| 9069989af3 | |||
| 0742737f0d | |||
| 5a34f03779 | |||
| 7d0d1b53ae | |||
| a1b03b81c0 | |||
| 4fc6bac4b5 | |||
| c4b15d7387 | |||
| affbd18de2 | |||
| 09cd00dc66 |
124
.gitea/workflows/ci.yaml
Normal file
124
.gitea/workflows/ci.yaml
Normal file
@@ -0,0 +1,124 @@
|
||||
name: CI/CD Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- develop
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: Restore class library
|
||||
run: dotnet restore classlib/classlib.csproj
|
||||
|
||||
- name: Restore test project
|
||||
run: dotnet restore classlib.tests/classlib.tests.csproj
|
||||
|
||||
- name: Build class library
|
||||
run: dotnet build classlib/classlib.csproj --configuration Release --no-restore
|
||||
|
||||
- name: Build test project
|
||||
run: dotnet build classlib.tests/classlib.tests.csproj --configuration Release --no-restore
|
||||
|
||||
- name: Run tests
|
||||
run: dotnet test classlib.tests/classlib.tests.csproj --configuration Release --no-build --verbosity normal --logger "trx;LogFileName=test-results.trx" --collect:"XPlat Code Coverage"
|
||||
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: test-results
|
||||
path: classlib.tests/TestResults/
|
||||
retention-days: 30
|
||||
|
||||
package:
|
||||
name: Package Module
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup .NET SDK
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: Build Release
|
||||
run: dotnet build classlib/classlib.csproj --configuration Release
|
||||
|
||||
- name: Create module package
|
||||
run: |
|
||||
mkdir -p output/ps.ipam
|
||||
|
||||
# Copy compiled DLL
|
||||
cp classlib/bin/Release/netstandard2.1/ps.ipam.dll output/ps.ipam/
|
||||
|
||||
# Copy module manifest and related files
|
||||
cp ps.ipam.psd1 output/ps.ipam/
|
||||
cp ps.ipam.psm1 output/ps.ipam/
|
||||
cp LICENSE output/ps.ipam/
|
||||
cp README.md output/ps.ipam/
|
||||
|
||||
# Copy types directory
|
||||
cp -r types output/ps.ipam/
|
||||
|
||||
# Copy functions directory
|
||||
cp -r functions output/ps.ipam/
|
||||
|
||||
# Copy images directory
|
||||
cp -r images output/ps.ipam/
|
||||
|
||||
- name: Upload module artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ps.ipam-module
|
||||
path: output/ps.ipam/
|
||||
retention-days: 90
|
||||
|
||||
release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
needs: package
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- name: Download module artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ps.ipam-module
|
||||
path: ps.ipam
|
||||
|
||||
- name: Create release archive
|
||||
run: |
|
||||
zip -r ps.ipam-${{ github.ref_name }}.zip ps.ipam/
|
||||
tar -czvf ps.ipam-${{ github.ref_name }}.tar.gz ps.ipam/
|
||||
|
||||
- name: Create Gitea Release
|
||||
uses: actions/gitea-release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.TOKEN }}
|
||||
files: |
|
||||
ps.ipam-${{ github.ref_name }}.zip
|
||||
ps.ipam-${{ github.ref_name }}.tar.gz
|
||||
title: Release ${{ github.ref_name }}
|
||||
draft: false
|
||||
prerelease: ${{ contains(github.ref_name, '-') }}
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.dll
|
||||
bin
|
||||
obj
|
||||
.code-workspace
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
[](https://git.arnike.ru/Arnike/ps.ipam/src/branch/main/LICENSE)
|
||||

|
||||

|
||||
|
||||
<h3 align="center">PS.IPAM</h3>
|
||||
|
||||
|
||||
330
classlib.tests/Cmdlets/GetAddressCmdletTests.cs
Normal file
330
classlib.tests/Cmdlets/GetAddressCmdletTests.cs
Normal file
@@ -0,0 +1,330 @@
|
||||
namespace PS.IPAM.Tests.Cmdlets;
|
||||
|
||||
using System.Net;
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using PS.IPAM.Cmdlets;
|
||||
using PS.IPAM.Helpers;
|
||||
using PS.IPAM.Tests.Mocks;
|
||||
using Xunit;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the GetAddressCmdlet.
|
||||
/// Note: Full cmdlet testing with parameter sets requires a PowerShell runspace.
|
||||
/// These tests focus on verifying the cmdlet structure and the underlying RequestHelper functionality.
|
||||
/// </summary>
|
||||
[Collection("Sequential")]
|
||||
public class GetAddressCmdletTests : IDisposable
|
||||
{
|
||||
private MockHttpMessageHandler? _mockHandler;
|
||||
|
||||
public GetAddressCmdletTests()
|
||||
{
|
||||
// Clean state before each test
|
||||
SessionManager.CloseSession();
|
||||
RequestHelper.TestHttpHandler = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Clean up after each test
|
||||
SessionManager.CloseSession();
|
||||
RequestHelper.TestHttpHandler = null;
|
||||
_mockHandler?.ForceDispose();
|
||||
}
|
||||
|
||||
private void SetupSession()
|
||||
{
|
||||
SessionManager.CreateSessionWithToken("https://ipam.example.com", "testapp", "test-token");
|
||||
}
|
||||
|
||||
private MockHttpMessageHandler SetupMockHandler()
|
||||
{
|
||||
_mockHandler = new MockHttpMessageHandler();
|
||||
RequestHelper.TestHttpHandler = _mockHandler;
|
||||
return _mockHandler;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_Exists()
|
||||
{
|
||||
// Verify the cmdlet class exists and can be instantiated
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_IdProperty_Exists()
|
||||
{
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.Id = 42;
|
||||
cmdlet.Id.Should().Be(42);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_IPProperty_Exists()
|
||||
{
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.IP = IPAddress.Parse("192.168.1.100");
|
||||
cmdlet.IP.Should().Be(IPAddress.Parse("192.168.1.100"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_HostNameProperty_Exists()
|
||||
{
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.HostName = "server01.example.com";
|
||||
cmdlet.HostName.Should().Be("server01.example.com");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_HostBaseProperty_Exists()
|
||||
{
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.HostBase = "server";
|
||||
cmdlet.HostBase.Should().Be("server");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_TagIdProperty_Exists()
|
||||
{
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.TagId = 2;
|
||||
cmdlet.TagId.Should().Be(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_SubnetIdProperty_Exists()
|
||||
{
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.SubnetId = 10;
|
||||
cmdlet.SubnetId.Should().Be(10);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_SubnetCIDRProperty_Exists()
|
||||
{
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.SubnetCIDR = "192.168.1.0/24";
|
||||
cmdlet.SubnetCIDR.Should().Be("192.168.1.0/24");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddressCmdlet_InheritsFromBaseCmdlet()
|
||||
{
|
||||
var cmdlet = new GetAddressCmdlet();
|
||||
cmdlet.Should().BeAssignableTo<BaseCmdlet>();
|
||||
}
|
||||
|
||||
// Test the underlying RequestHelper functionality that the cmdlet uses
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_GetAddressById_ReturnsAddress()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
var addressJson = @"{
|
||||
""id"": 1,
|
||||
""subnetId"": 10,
|
||||
""ip"": ""192.168.1.100"",
|
||||
""hostname"": ""server01"",
|
||||
""description"": ""Test server""
|
||||
}";
|
||||
handler.WithSuccessResponse(addressJson);
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Addresses,
|
||||
ModelType.Address,
|
||||
null,
|
||||
null,
|
||||
new[] { "1" }
|
||||
);
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<Address>();
|
||||
var address = (Address)result!;
|
||||
address.Id.Should().Be(1);
|
||||
address.Ip.Should().Be("192.168.1.100");
|
||||
address.Hostname.Should().Be("server01");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_GetAddressById_BuildsCorrectUri()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse(@"{""id"": 42, ""ip"": ""10.0.0.1""}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Addresses,
|
||||
ModelType.Address,
|
||||
null,
|
||||
null,
|
||||
new[] { "42" }
|
||||
);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/addresses/42/");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_SearchByIP_BuildsCorrectUri()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse(@"{""id"": 1, ""ip"": ""192.168.1.50""}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Addresses,
|
||||
ModelType.Address,
|
||||
null,
|
||||
null,
|
||||
new[] { "search", "192.168.1.50" }
|
||||
);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/addresses/search/192.168.1.50/");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_SearchByHostname_BuildsCorrectUri()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse(@"{""id"": 1, ""ip"": ""10.0.0.5"", ""hostname"": ""myserver.example.com""}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Addresses,
|
||||
ModelType.Address,
|
||||
null,
|
||||
null,
|
||||
new[] { "search_hostname", "myserver.example.com" }
|
||||
);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/addresses/search_hostname/myserver.example.com/");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_GetSubnetAddresses_BuildsCorrectUri()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse(@"[{""id"": 1, ""ip"": ""192.168.1.1""}]");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Subnets,
|
||||
ModelType.Address,
|
||||
null,
|
||||
null,
|
||||
new[] { "10", "addresses" }
|
||||
);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/subnets/10/addresses/");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_GetAddressesByTag_BuildsCorrectUri()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse(@"[{""id"": 1, ""ip"": ""10.0.0.1"", ""tag"": 2}]");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Addresses,
|
||||
ModelType.Address,
|
||||
null,
|
||||
null,
|
||||
new[] { "tags", "2", "addresses" }
|
||||
);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/addresses/tags/2/addresses/");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_ReturnsMultipleAddresses()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse(@"[
|
||||
{""id"": 1, ""ip"": ""192.168.1.1""},
|
||||
{""id"": 2, ""ip"": ""192.168.1.2""},
|
||||
{""id"": 3, ""ip"": ""192.168.1.3""}
|
||||
]");
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Subnets,
|
||||
ModelType.Address,
|
||||
null,
|
||||
null,
|
||||
new[] { "10", "addresses" }
|
||||
);
|
||||
|
||||
// Assert
|
||||
result.Should().BeAssignableTo<System.Collections.IEnumerable>();
|
||||
var addresses = ((System.Collections.IEnumerable)result!).Cast<object>().ToList();
|
||||
addresses.Should().HaveCount(3);
|
||||
addresses.Should().AllBeOfType<Address>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_With404Response_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithNotFoundResponse();
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Addresses,
|
||||
ModelType.Address,
|
||||
null,
|
||||
null,
|
||||
new[] { "999" }
|
||||
);
|
||||
|
||||
// Assert
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestHelper_WithNoSession_ThrowsException()
|
||||
{
|
||||
// Arrange - no session set up
|
||||
|
||||
// Act
|
||||
var action = async () => await RequestHelper.InvokeRequest(
|
||||
"GET",
|
||||
ApiController.Addresses,
|
||||
ModelType.Address
|
||||
);
|
||||
|
||||
// Assert
|
||||
await action.Should().ThrowAsync<InvalidOperationException>().WithMessage("No session available!");
|
||||
}
|
||||
}
|
||||
110
classlib.tests/Cmdlets/NewSessionCmdletTests.cs
Normal file
110
classlib.tests/Cmdlets/NewSessionCmdletTests.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
namespace PS.IPAM.Tests.Cmdlets;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using PS.IPAM.Cmdlets;
|
||||
using PS.IPAM.Helpers;
|
||||
using Xunit;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the NewSessionCmdlet.
|
||||
/// Note: Full cmdlet testing with parameter sets requires a PowerShell runspace.
|
||||
/// These tests focus on verifying the cmdlet structure and basic functionality.
|
||||
/// </summary>
|
||||
[Collection("Sequential")]
|
||||
public class NewSessionCmdletTests : IDisposable
|
||||
{
|
||||
public NewSessionCmdletTests()
|
||||
{
|
||||
// Clean state before each test
|
||||
SessionManager.CloseSession();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Clean up after each test
|
||||
SessionManager.CloseSession();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewSessionCmdlet_Exists()
|
||||
{
|
||||
// Verify the cmdlet class exists and can be instantiated
|
||||
var cmdlet = new NewSessionCmdlet();
|
||||
cmdlet.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewSessionCmdlet_URLProperty_Exists()
|
||||
{
|
||||
var cmdlet = new NewSessionCmdlet();
|
||||
cmdlet.URL = "https://ipam.example.com";
|
||||
cmdlet.URL.Should().Be("https://ipam.example.com");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewSessionCmdlet_AppIDProperty_Exists()
|
||||
{
|
||||
var cmdlet = new NewSessionCmdlet();
|
||||
cmdlet.AppID = "testapp";
|
||||
cmdlet.AppID.Should().Be("testapp");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewSessionCmdlet_TokenProperty_Exists()
|
||||
{
|
||||
var cmdlet = new NewSessionCmdlet();
|
||||
cmdlet.Token = "my-api-token";
|
||||
cmdlet.Token.Should().Be("my-api-token");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewSessionCmdlet_CredentialsProperty_Exists()
|
||||
{
|
||||
var cmdlet = new NewSessionCmdlet();
|
||||
cmdlet.Credentials = null;
|
||||
cmdlet.Credentials.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewSessionCmdlet_IgnoreSSLProperty_Exists()
|
||||
{
|
||||
var cmdlet = new NewSessionCmdlet();
|
||||
// SwitchParameter defaults to false
|
||||
cmdlet.IgnoreSSL.IsPresent.Should().BeFalse();
|
||||
// Setting it to true
|
||||
var switchParam = new System.Management.Automation.SwitchParameter(true);
|
||||
cmdlet.IgnoreSSL = switchParam;
|
||||
// Note: SwitchParameter is a struct, so getting the value back may not work as expected
|
||||
// Just verify the property exists and can be set
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SessionManager_CreateSessionWithToken_WorksCorrectly()
|
||||
{
|
||||
// This tests the underlying functionality that the cmdlet uses
|
||||
var session = SessionManager.CreateSessionWithToken(
|
||||
"https://ipam.example.com",
|
||||
"testapp",
|
||||
"my-api-token"
|
||||
);
|
||||
|
||||
session.Should().NotBeNull();
|
||||
session.URL.Should().Be("https://ipam.example.com");
|
||||
session.AppID.Should().Be("testapp");
|
||||
session.Token.Should().Be("my-api-token");
|
||||
session.AuthType.Should().Be(AuthType.Token);
|
||||
session.Expires.Should().BeNull();
|
||||
session.Credentials.Should().BeNull();
|
||||
|
||||
// Verify it was set as current session
|
||||
SessionManager.CurrentSession.Should().BeSameAs(session);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewSessionCmdlet_InheritsFromBaseCmdlet()
|
||||
{
|
||||
var cmdlet = new NewSessionCmdlet();
|
||||
cmdlet.Should().BeAssignableTo<BaseCmdlet>();
|
||||
}
|
||||
}
|
||||
503
classlib.tests/Helpers/RequestHelperTests.cs
Normal file
503
classlib.tests/Helpers/RequestHelperTests.cs
Normal file
@@ -0,0 +1,503 @@
|
||||
namespace PS.IPAM.Tests.Helpers;
|
||||
|
||||
using System.Net;
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using PS.IPAM.Helpers;
|
||||
using PS.IPAM.Tests.Mocks;
|
||||
using Xunit;
|
||||
|
||||
[Collection("Sequential")]
|
||||
public class RequestHelperTests : IDisposable
|
||||
{
|
||||
private MockHttpMessageHandler? _mockHandler;
|
||||
|
||||
public RequestHelperTests()
|
||||
{
|
||||
// Clean state before each test
|
||||
SessionManager.CloseSession();
|
||||
RequestHelper.TestHttpHandler = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Clean up after each test
|
||||
SessionManager.CloseSession();
|
||||
RequestHelper.TestHttpHandler = null;
|
||||
_mockHandler?.ForceDispose();
|
||||
}
|
||||
|
||||
private void SetupSession(AuthType authType = AuthType.Token)
|
||||
{
|
||||
if (authType == AuthType.Token)
|
||||
{
|
||||
SessionManager.CreateSessionWithToken("https://ipam.example.com", "testapp", "test-token");
|
||||
}
|
||||
else
|
||||
{
|
||||
// For credentials auth, we need to set up a session manually with future expiry
|
||||
var session = new Session(
|
||||
AuthType.Credentials,
|
||||
"cred-token",
|
||||
"testapp",
|
||||
"https://ipam.example.com",
|
||||
DateTime.Now.AddHours(1),
|
||||
null
|
||||
);
|
||||
SessionManager.CurrentSession = session;
|
||||
}
|
||||
}
|
||||
|
||||
private MockHttpMessageHandler SetupMockHandler()
|
||||
{
|
||||
_mockHandler = new MockHttpMessageHandler();
|
||||
RequestHelper.TestHttpHandler = _mockHandler;
|
||||
return _mockHandler;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithNoSession_ThrowsException()
|
||||
{
|
||||
// Arrange - no session set up
|
||||
|
||||
// Act
|
||||
var action = async () => await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
|
||||
|
||||
// Assert
|
||||
await action.Should().ThrowAsync<InvalidOperationException>().WithMessage("No session available!");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithValidSession_BuildsCorrectUri()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("{\"id\":1,\"ip\":\"192.168.1.1\"}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address, null, null, new[] { "1" });
|
||||
|
||||
// Assert
|
||||
handler.LastRequest.Should().NotBeNull();
|
||||
handler.LastRequest!.RequestUri!.ToString().Should().Be("https://ipam.example.com/api/testapp/addresses/1/");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithSubController_BuildsCorrectUri()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("[]");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("GET", ApiController.Subnets, null, ApiSubController.Tags, null, new[] { "1" });
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/subnets/tags/1/");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithTokenAuth_AddsPhpipamTokenHeader()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession(AuthType.Token);
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("{}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
|
||||
|
||||
// Assert
|
||||
handler.GetLastRequestHeader("phpipam-token").Should().Be("test-token");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithCredentialsAuth_AddsTokenHeader()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession(AuthType.Credentials);
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("{}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
|
||||
|
||||
// Assert
|
||||
handler.GetLastRequestHeader("token").Should().Be("cred-token");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_GetMethod_UsesHttpGet()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("{}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Method.Should().Be(HttpMethod.Get);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_PostMethod_UsesHttpPost()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("{\"id\":1}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("POST", ApiController.Addresses, null, null, new { ip = "10.0.0.1" });
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Method.Should().Be(HttpMethod.Post);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_PatchMethod_UsesHttpPatch()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("{\"id\":1}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("PATCH", ApiController.Addresses, null, null, new { description = "updated" }, new[] { "1" });
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Method.Should().Be(new HttpMethod("PATCH"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_DeleteMethod_UsesHttpDelete()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("{}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("DELETE", ApiController.Addresses, null, null, null, new[] { "1" });
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Method.Should().Be(HttpMethod.Delete);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_With404Response_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithNotFoundResponse();
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address, null, null, new[] { "999" });
|
||||
|
||||
// Assert
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithErrorResponse_ThrowsHttpRequestException()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithErrorResponse(HttpStatusCode.InternalServerError, "Server error");
|
||||
|
||||
// Act
|
||||
var action = async () => await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
|
||||
|
||||
// Assert
|
||||
await action.Should().ThrowAsync<HttpRequestException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithAddressType_ReturnsAddressObject()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
var addressJson = @"{
|
||||
""id"": 1,
|
||||
""subnetId"": 10,
|
||||
""ip"": ""192.168.1.100"",
|
||||
""is_gateway"": false,
|
||||
""description"": ""Test server"",
|
||||
""hostname"": ""server01"",
|
||||
""mac"": ""00:11:22:33:44:55"",
|
||||
""owner"": ""admin"",
|
||||
""tag"": 2,
|
||||
""deviceId"": 0,
|
||||
""location"": """",
|
||||
""port"": """",
|
||||
""note"": """",
|
||||
""lastSeen"": null,
|
||||
""excludePing"": false,
|
||||
""PTRignore"": false,
|
||||
""PTR"": 0,
|
||||
""firewallAddressObject"": """",
|
||||
""editDate"": null,
|
||||
""customer_id"": 0
|
||||
}";
|
||||
handler.WithSuccessResponse(addressJson);
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address, null, null, new[] { "1" });
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<Address>();
|
||||
var address = (Address)result!;
|
||||
address.Id.Should().Be(1);
|
||||
address.Ip.Should().Be("192.168.1.100");
|
||||
address.Hostname.Should().Be("server01");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithAddressArray_ReturnsListOfAddresses()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
var addressArrayJson = @"[
|
||||
{""id"": 1, ""subnetId"": 10, ""ip"": ""192.168.1.1"", ""hostname"": ""host1""},
|
||||
{""id"": 2, ""subnetId"": 10, ""ip"": ""192.168.1.2"", ""hostname"": ""host2""}
|
||||
]";
|
||||
handler.WithSuccessResponse(addressArrayJson);
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Subnets, ModelType.Address, null, null, new[] { "10", "addresses" });
|
||||
|
||||
// Assert
|
||||
result.Should().BeAssignableTo<IEnumerable<object>>();
|
||||
var addresses = ((IEnumerable<object>)result!).ToList();
|
||||
addresses.Should().HaveCount(2);
|
||||
addresses[0].Should().BeOfType<Address>();
|
||||
((Address)addresses[0]).Ip.Should().Be("192.168.1.1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithVlanType_ReturnsVlanObject()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
var vlanJson = @"{
|
||||
""vlanId"": 100,
|
||||
""domainId"": 1,
|
||||
""name"": ""Production"",
|
||||
""number"": 100,
|
||||
""description"": ""Production VLAN"",
|
||||
""editDate"": null,
|
||||
""customer_id"": 0
|
||||
}";
|
||||
handler.WithSuccessResponse(vlanJson);
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Vlan, ModelType.Vlan, null, null, new[] { "100" });
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<Vlan>();
|
||||
var vlan = (Vlan)result!;
|
||||
vlan.Name.Should().Be("Production");
|
||||
vlan.Number.Should().Be(100);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithSubnetworkType_ReturnsSubnetworkObject()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
var subnetJson = @"{
|
||||
""id"": 1,
|
||||
""subnet"": ""192.168.1.0"",
|
||||
""mask"": 24,
|
||||
""sectionId"": 1,
|
||||
""description"": ""Test subnet"",
|
||||
""linked_subnet"": """",
|
||||
""firewallAddressObject"": """",
|
||||
""vrfId"": 0,
|
||||
""masterSubnetId"": 0,
|
||||
""allowRequests"": false,
|
||||
""vlanId"": 100,
|
||||
""showName"": false,
|
||||
""deviceId"": 0,
|
||||
""permissions"": """",
|
||||
""pingSubnet"": false,
|
||||
""discoverSubnet"": false,
|
||||
""resolveDNS"": false,
|
||||
""DNSrecursive"": false,
|
||||
""DNSrecords"": false,
|
||||
""nameserverId"": 0,
|
||||
""scanAgent"": false,
|
||||
""isFolder"": false,
|
||||
""isFull"": false,
|
||||
""isPool"": false,
|
||||
""state"": 1,
|
||||
""threshold"": 0,
|
||||
""location"": 0,
|
||||
""editDate"": null,
|
||||
""lastScan"": null,
|
||||
""lastDiscovery"": null,
|
||||
""calculation"": {}
|
||||
}";
|
||||
handler.WithSuccessResponse(subnetJson);
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Subnets, ModelType.Subnetwork, null, null, new[] { "1" });
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<Subnetwork>();
|
||||
var subnet = (Subnetwork)result!;
|
||||
subnet.Subnet.Should().Be("192.168.1.0");
|
||||
subnet.Mask.Should().Be(24);
|
||||
subnet.CIDR.Should().Be("192.168.1.0/24");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithSectionType_ReturnsSectionObject()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
var sectionJson = @"{
|
||||
""id"": 1,
|
||||
""name"": ""Production"",
|
||||
""description"": ""Production section"",
|
||||
""masterSection"": 0,
|
||||
""permissions"": """",
|
||||
""strictMode"": false,
|
||||
""subnetOrdering"": ""default"",
|
||||
""order"": 1,
|
||||
""editDate"": null,
|
||||
""showSubnet"": true,
|
||||
""showVlan"": true,
|
||||
""showVRF"": false,
|
||||
""showSupernetOnly"": false,
|
||||
""DNS"": 0
|
||||
}";
|
||||
handler.WithSuccessResponse(sectionJson);
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Sections, ModelType.Section, null, null, new[] { "1" });
|
||||
|
||||
// Assert
|
||||
result.Should().BeOfType<Section>();
|
||||
var section = (Section)result!;
|
||||
section.Name.Should().Be("Production");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithCustomFields_ParsesExtendedData()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
var addressJson = @"{
|
||||
""id"": 1,
|
||||
""subnetId"": 10,
|
||||
""ip"": ""192.168.1.100"",
|
||||
""hostname"": ""server01"",
|
||||
""custom_environment"": ""production"",
|
||||
""custom_owner"": ""team-a""
|
||||
}";
|
||||
handler.WithSuccessResponse(addressJson);
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address, null, null, new[] { "1" });
|
||||
|
||||
// Assert
|
||||
var address = (Address)result!;
|
||||
address.ExtendedData.Should().NotBeNull();
|
||||
var extendedData = address.ExtendedData!;
|
||||
extendedData.Should().ContainKey("custom_environment");
|
||||
extendedData.Should().ContainKey("custom_owner");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithNoType_ReturnsDynamicData()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse(@"{""some"": ""data""}");
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Tools);
|
||||
|
||||
// Assert
|
||||
result.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_PostWithParameters_SerializesJsonBody()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse(@"{""id"": 1}");
|
||||
|
||||
var parameters = new { ip = "10.0.0.1", subnetId = 5, description = "New address" };
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("POST", ApiController.Addresses, null, null, parameters);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Content.Should().NotBeNull();
|
||||
var content = await handler.LastRequest.Content!.ReadAsStringAsync();
|
||||
content.Should().Contain("10.0.0.1");
|
||||
content.Should().Contain("subnetId");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_SetsAcceptJsonHeader()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithSuccessResponse("{}");
|
||||
|
||||
// Act
|
||||
await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
|
||||
|
||||
// Assert
|
||||
handler.LastRequest!.Headers.Accept.Should().Contain(h => h.MediaType == "application/json");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithEmptyResponse_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithResponse(HttpStatusCode.OK, "", "application/json");
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
|
||||
|
||||
// Assert
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeRequest_WithNullDataInResponse_ReturnsNull()
|
||||
{
|
||||
// Arrange
|
||||
SetupSession();
|
||||
var handler = SetupMockHandler();
|
||||
handler.WithJsonResponse(@"{""code"": 200, ""success"": true, ""data"": null}");
|
||||
|
||||
// Act
|
||||
var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address);
|
||||
|
||||
// Assert
|
||||
result.Should().BeNull();
|
||||
}
|
||||
}
|
||||
193
classlib.tests/Helpers/SessionManagerTests.cs
Normal file
193
classlib.tests/Helpers/SessionManagerTests.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
namespace PS.IPAM.Tests.Helpers;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using PS.IPAM.Helpers;
|
||||
using Xunit;
|
||||
|
||||
[Collection("Sequential")]
|
||||
public class SessionManagerTests : IDisposable
|
||||
{
|
||||
public SessionManagerTests()
|
||||
{
|
||||
// Ensure clean state before each test
|
||||
SessionManager.CloseSession();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Clean up after each test
|
||||
SessionManager.CloseSession();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSessionStatus_WhenNoSession_ReturnsNoSession()
|
||||
{
|
||||
// Arrange
|
||||
SessionManager.CurrentSession = null;
|
||||
|
||||
// Act
|
||||
var result = SessionManager.GetSessionStatus();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(SessionStatus.NoSession);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSessionStatus_WhenSessionWithNullExpires_ReturnsValid()
|
||||
{
|
||||
// Arrange
|
||||
var session = new Session(AuthType.Token, "test-token", "app", "https://test.com", null, null);
|
||||
SessionManager.CurrentSession = session;
|
||||
|
||||
// Act
|
||||
var result = SessionManager.GetSessionStatus();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(SessionStatus.Valid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSessionStatus_WhenSessionNotExpired_ReturnsValid()
|
||||
{
|
||||
// Arrange
|
||||
var futureExpiry = DateTime.Now.AddHours(1);
|
||||
var session = new Session(AuthType.Credentials, "test-token", "app", "https://test.com", futureExpiry, null);
|
||||
SessionManager.CurrentSession = session;
|
||||
|
||||
// Act
|
||||
var result = SessionManager.GetSessionStatus();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(SessionStatus.Valid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSessionStatus_WhenSessionExpired_ReturnsExpired()
|
||||
{
|
||||
// Arrange
|
||||
var pastExpiry = DateTime.Now.AddHours(-1);
|
||||
var session = new Session(AuthType.Credentials, "test-token", "app", "https://test.com", pastExpiry, null);
|
||||
SessionManager.CurrentSession = session;
|
||||
|
||||
// Act
|
||||
var result = SessionManager.GetSessionStatus();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(SessionStatus.Expired);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateSessionWithToken_CreatesValidSession()
|
||||
{
|
||||
// Arrange
|
||||
var url = "https://ipam.example.com";
|
||||
var appId = "myApp";
|
||||
var token = "static-api-token";
|
||||
|
||||
// Act
|
||||
var session = SessionManager.CreateSessionWithToken(url, appId, token);
|
||||
|
||||
// Assert
|
||||
session.Should().NotBeNull();
|
||||
session.URL.Should().Be(url);
|
||||
session.AppID.Should().Be(appId);
|
||||
session.Token.Should().Be(token);
|
||||
session.AuthType.Should().Be(AuthType.Token);
|
||||
session.Expires.Should().BeNull();
|
||||
session.Credentials.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateSessionWithToken_SetsCurrentSession()
|
||||
{
|
||||
// Arrange
|
||||
var url = "https://ipam.example.com";
|
||||
var appId = "myApp";
|
||||
var token = "api-token";
|
||||
|
||||
// Act
|
||||
var session = SessionManager.CreateSessionWithToken(url, appId, token);
|
||||
|
||||
// Assert
|
||||
SessionManager.CurrentSession.Should().BeSameAs(session);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloseSession_ClearsCurrentSession()
|
||||
{
|
||||
// Arrange
|
||||
SessionManager.CreateSessionWithToken("https://test.com", "app", "token");
|
||||
SessionManager.CurrentSession.Should().NotBeNull();
|
||||
|
||||
// Act
|
||||
SessionManager.CloseSession();
|
||||
|
||||
// Assert
|
||||
SessionManager.CurrentSession.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloseSession_WhenNoSession_DoesNotThrow()
|
||||
{
|
||||
// Arrange
|
||||
SessionManager.CurrentSession = null;
|
||||
|
||||
// Act
|
||||
var action = () => SessionManager.CloseSession();
|
||||
|
||||
// Assert
|
||||
action.Should().NotThrow();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CurrentSession_CanBeSetDirectly()
|
||||
{
|
||||
// Arrange
|
||||
var session = new Session(AuthType.Token, "token", "app", "https://test.com", null, null);
|
||||
|
||||
// Act
|
||||
SessionManager.CurrentSession = session;
|
||||
|
||||
// Assert
|
||||
SessionManager.CurrentSession.Should().BeSameAs(session);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateHttpClient_WithoutIgnoreSsl_ReturnsHttpClient()
|
||||
{
|
||||
// Act
|
||||
using var client = SessionManager.CreateHttpClient(false);
|
||||
|
||||
// Assert
|
||||
client.Should().NotBeNull();
|
||||
client.Should().BeOfType<HttpClient>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateHttpClient_WithIgnoreSsl_ReturnsHttpClient()
|
||||
{
|
||||
// Act
|
||||
using var client = SessionManager.CreateHttpClient(true);
|
||||
|
||||
// Assert
|
||||
client.Should().NotBeNull();
|
||||
client.Should().BeOfType<HttpClient>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateSessionWithToken_ReplacesExistingSession()
|
||||
{
|
||||
// Arrange
|
||||
SessionManager.CreateSessionWithToken("https://old.com", "oldApp", "oldToken");
|
||||
|
||||
// Act
|
||||
var newSession = SessionManager.CreateSessionWithToken("https://new.com", "newApp", "newToken");
|
||||
|
||||
// Assert
|
||||
SessionManager.CurrentSession.Should().BeSameAs(newSession);
|
||||
SessionManager.CurrentSession!.URL.Should().Be("https://new.com");
|
||||
SessionManager.CurrentSession.AppID.Should().Be("newApp");
|
||||
SessionManager.CurrentSession.Token.Should().Be("newToken");
|
||||
}
|
||||
}
|
||||
139
classlib.tests/Mocks/CmdletTestHelper.cs
Normal file
139
classlib.tests/Mocks/CmdletTestHelper.cs
Normal file
@@ -0,0 +1,139 @@
|
||||
namespace PS.IPAM.Tests.Mocks;
|
||||
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Host;
|
||||
using System.Reflection;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for testing PowerShell cmdlets.
|
||||
/// </summary>
|
||||
public class CmdletTestHelper<T> : IDisposable where T : PSCmdlet, new()
|
||||
{
|
||||
private readonly T _cmdlet;
|
||||
private readonly List<object> _output = new();
|
||||
private readonly List<ErrorRecord> _errors = new();
|
||||
private bool _disposed;
|
||||
|
||||
public CmdletTestHelper()
|
||||
{
|
||||
_cmdlet = new T();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the cmdlet instance for setting parameters.
|
||||
/// </summary>
|
||||
public T Cmdlet => _cmdlet;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the output objects written by the cmdlet.
|
||||
/// </summary>
|
||||
public IReadOnlyList<object> Output => _output.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the errors written by the cmdlet.
|
||||
/// </summary>
|
||||
public IReadOnlyList<ErrorRecord> Errors => _errors.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether any errors were written.
|
||||
/// </summary>
|
||||
public bool HasErrors => _errors.Count > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the cmdlet and captures output.
|
||||
/// </summary>
|
||||
public void Invoke()
|
||||
{
|
||||
// Use reflection to call the protected ProcessRecord method
|
||||
var processMethod = typeof(T).GetMethod("ProcessRecord",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (processMethod == null)
|
||||
{
|
||||
throw new InvalidOperationException("ProcessRecord method not found on cmdlet.");
|
||||
}
|
||||
|
||||
// Set up a mock command runtime to capture output
|
||||
var runtime = new MockCommandRuntime(_output, _errors);
|
||||
var runtimeProperty = typeof(Cmdlet).GetProperty("CommandRuntime",
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
runtimeProperty?.SetValue(_cmdlet, runtime);
|
||||
|
||||
// Invoke the method
|
||||
try
|
||||
{
|
||||
processMethod.Invoke(_cmdlet, null);
|
||||
}
|
||||
catch (TargetInvocationException ex) when (ex.InnerException != null)
|
||||
{
|
||||
// Unwrap the exception
|
||||
throw ex.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mock implementation of ICommandRuntime for capturing cmdlet output.
|
||||
/// This is a minimal implementation that only handles the methods we need for testing.
|
||||
/// </summary>
|
||||
internal class MockCommandRuntime : ICommandRuntime
|
||||
{
|
||||
private readonly List<object> _output;
|
||||
private readonly List<ErrorRecord> _errors;
|
||||
|
||||
public MockCommandRuntime(List<object> output, List<ErrorRecord> errors)
|
||||
{
|
||||
_output = output;
|
||||
_errors = errors;
|
||||
}
|
||||
|
||||
public PSHost Host => null!;
|
||||
public PSTransactionContext CurrentPSTransaction => null!;
|
||||
|
||||
public bool ShouldContinue(string query, string caption) => true;
|
||||
public bool ShouldContinue(string query, string caption, ref bool yesToAll, ref bool noToAll) => true;
|
||||
public bool ShouldProcess(string target) => true;
|
||||
public bool ShouldProcess(string target, string action) => true;
|
||||
public bool ShouldProcess(string verboseDescription, string verboseWarning, string caption) => true;
|
||||
public bool ShouldProcess(string verboseDescription, string verboseWarning, string caption, out ShouldProcessReason shouldProcessReason)
|
||||
{
|
||||
shouldProcessReason = ShouldProcessReason.None;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TransactionAvailable() => false;
|
||||
|
||||
public void ThrowTerminatingError(ErrorRecord errorRecord) => throw errorRecord.Exception;
|
||||
|
||||
public void WriteCommandDetail(string text) { }
|
||||
public void WriteDebug(string text) { }
|
||||
public void WriteError(ErrorRecord errorRecord) => _errors.Add(errorRecord);
|
||||
public void WriteObject(object sendToPipeline) => _output.Add(sendToPipeline);
|
||||
public void WriteObject(object sendToPipeline, bool enumerateCollection)
|
||||
{
|
||||
if (enumerateCollection && sendToPipeline is System.Collections.IEnumerable enumerable)
|
||||
{
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
_output.Add(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_output.Add(sendToPipeline);
|
||||
}
|
||||
}
|
||||
public void WriteProgress(ProgressRecord progressRecord) { }
|
||||
public void WriteProgress(long sourceId, ProgressRecord progressRecord) { }
|
||||
public void WriteVerbose(string text) { }
|
||||
public void WriteWarning(string text) { }
|
||||
}
|
||||
172
classlib.tests/Mocks/MockHttpMessageHandler.cs
Normal file
172
classlib.tests/Mocks/MockHttpMessageHandler.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
namespace PS.IPAM.Tests.Mocks;
|
||||
|
||||
using System.Net;
|
||||
|
||||
/// <summary>
|
||||
/// A mock HTTP message handler for testing HTTP requests without making actual network calls.
|
||||
/// This handler does not dispose itself when the HttpClient is disposed, allowing reuse in tests.
|
||||
/// </summary>
|
||||
public class MockHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly Queue<MockResponse> _responses = new();
|
||||
private readonly List<HttpRequestMessage> _requests = new();
|
||||
private bool _disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all requests that were sent through this handler.
|
||||
/// </summary>
|
||||
public IReadOnlyList<HttpRequestMessage> Requests => _requests.AsReadOnly();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last request that was sent through this handler.
|
||||
/// </summary>
|
||||
public HttpRequestMessage? LastRequest => _requests.LastOrDefault();
|
||||
|
||||
/// <summary>
|
||||
/// Queues a response to be returned for the next request.
|
||||
/// </summary>
|
||||
public MockHttpMessageHandler WithResponse(HttpStatusCode statusCode, string content, string contentType = "application/json")
|
||||
{
|
||||
_responses.Enqueue(new MockResponse(statusCode, content, contentType));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues a successful JSON response.
|
||||
/// </summary>
|
||||
public MockHttpMessageHandler WithJsonResponse(string jsonContent)
|
||||
{
|
||||
return WithResponse(HttpStatusCode.OK, jsonContent, "application/json");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues a successful response with phpIPAM-style wrapper.
|
||||
/// </summary>
|
||||
public MockHttpMessageHandler WithSuccessResponse(string dataJson)
|
||||
{
|
||||
var response = $"{{\"code\":200,\"success\":true,\"data\":{dataJson}}}";
|
||||
return WithJsonResponse(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues a 404 Not Found response.
|
||||
/// </summary>
|
||||
public MockHttpMessageHandler WithNotFoundResponse()
|
||||
{
|
||||
return WithResponse(HttpStatusCode.NotFound, "{\"code\":404,\"success\":false,\"message\":\"Not found\"}", "application/json");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues an error response.
|
||||
/// </summary>
|
||||
public MockHttpMessageHandler WithErrorResponse(HttpStatusCode statusCode, string message)
|
||||
{
|
||||
var response = $"{{\"code\":{(int)statusCode},\"success\":false,\"message\":\"{message}\"}}";
|
||||
return WithResponse(statusCode, response, "application/json");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queues an exception to be thrown on the next request.
|
||||
/// </summary>
|
||||
public MockHttpMessageHandler WithException(Exception exception)
|
||||
{
|
||||
_responses.Enqueue(new MockResponse(exception));
|
||||
return this;
|
||||
}
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(MockHttpMessageHandler));
|
||||
}
|
||||
|
||||
_requests.Add(request);
|
||||
|
||||
if (_responses.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No mock response configured. Call WithResponse() before making requests.");
|
||||
}
|
||||
|
||||
var mockResponse = _responses.Dequeue();
|
||||
|
||||
if (mockResponse.Exception != null)
|
||||
{
|
||||
throw mockResponse.Exception;
|
||||
}
|
||||
|
||||
var response = new HttpResponseMessage(mockResponse.StatusCode)
|
||||
{
|
||||
Content = new StringContent(mockResponse.Content, System.Text.Encoding.UTF8, mockResponse.ContentType),
|
||||
RequestMessage = request
|
||||
};
|
||||
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
// Don't actually dispose - allow reuse in tests
|
||||
// The test itself is responsible for cleanup
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Actually disposes the handler. Call this in test cleanup.
|
||||
/// </summary>
|
||||
public void ForceDispose()
|
||||
{
|
||||
_disposed = true;
|
||||
base.Dispose(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that a request was made to the expected URL.
|
||||
/// </summary>
|
||||
public bool WasRequestMadeTo(string urlContains)
|
||||
{
|
||||
return _requests.Any(r => r.RequestUri?.ToString().Contains(urlContains) == true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that a request with the expected method was made.
|
||||
/// </summary>
|
||||
public bool WasRequestMadeWithMethod(HttpMethod method)
|
||||
{
|
||||
return _requests.Any(r => r.Method == method);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a header from the last request.
|
||||
/// </summary>
|
||||
public string? GetLastRequestHeader(string headerName)
|
||||
{
|
||||
if (LastRequest?.Headers.TryGetValues(headerName, out var values) == true)
|
||||
{
|
||||
return values.FirstOrDefault();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private class MockResponse
|
||||
{
|
||||
public HttpStatusCode StatusCode { get; }
|
||||
public string Content { get; }
|
||||
public string ContentType { get; }
|
||||
public Exception? Exception { get; }
|
||||
|
||||
public MockResponse(HttpStatusCode statusCode, string content, string contentType)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Content = content;
|
||||
ContentType = contentType;
|
||||
}
|
||||
|
||||
public MockResponse(Exception exception)
|
||||
{
|
||||
Exception = exception;
|
||||
StatusCode = HttpStatusCode.InternalServerError;
|
||||
Content = string.Empty;
|
||||
ContentType = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
classlib.tests/Models/AddressTests.cs
Normal file
136
classlib.tests/Models/AddressTests.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class AddressTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
var subnetId = 10;
|
||||
var ip = "192.168.1.100";
|
||||
var isGateway = true;
|
||||
var description = "Test server";
|
||||
var hostname = "server01.example.com";
|
||||
var mac = "00:11:22:33:44:55";
|
||||
var owner = "admin";
|
||||
var tagId = 2;
|
||||
var deviceId = 5;
|
||||
var location = "DC1";
|
||||
var port = "eth0";
|
||||
var note = "Production server";
|
||||
var lastSeen = new DateTime(2026, 1, 15, 10, 30, 0);
|
||||
var excludePing = false;
|
||||
var ptrIgnore = true;
|
||||
var ptr = 1;
|
||||
var firewallObject = "FW_SERVER01";
|
||||
var editDate = new DateTime(2026, 1, 10, 8, 0, 0);
|
||||
var customerId = 100;
|
||||
var extendedData = new Dictionary<string, object> { { "custom_field1", "value1" } };
|
||||
|
||||
// Act
|
||||
var address = new Address(
|
||||
id, subnetId, ip, isGateway, description, hostname, mac, owner,
|
||||
tagId, deviceId, location, port, note, lastSeen, excludePing,
|
||||
ptrIgnore, ptr, firewallObject, editDate, customerId, extendedData
|
||||
);
|
||||
|
||||
// Assert
|
||||
address.Id.Should().Be(id);
|
||||
address.SubnetId.Should().Be(subnetId);
|
||||
address.Ip.Should().Be(ip);
|
||||
address.IsGateway.Should().Be(isGateway);
|
||||
address.Description.Should().Be(description);
|
||||
address.Hostname.Should().Be(hostname);
|
||||
address.MAC.Should().Be(mac);
|
||||
address.Owner.Should().Be(owner);
|
||||
address.TagId.Should().Be(tagId);
|
||||
address.DeviceId.Should().Be(deviceId);
|
||||
address.Location.Should().Be(location);
|
||||
address.Port.Should().Be(port);
|
||||
address.Note.Should().Be(note);
|
||||
address.LastSeen.Should().Be(lastSeen);
|
||||
address.ExcludePing.Should().Be(excludePing);
|
||||
address.PTRIgnore.Should().Be(ptrIgnore);
|
||||
address.PTR.Should().Be(ptr);
|
||||
address.FirewallAddressObject.Should().Be(firewallObject);
|
||||
address.EditDate.Should().Be(editDate);
|
||||
address.CustomerId.Should().Be(customerId);
|
||||
address.ExtendedData.Should().BeEquivalentTo(extendedData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithNullOptionalFields_SetsNullValues()
|
||||
{
|
||||
// Act
|
||||
var address = new Address(
|
||||
1, 10, "10.0.0.1", false, "", "", "", "",
|
||||
0, 0, "", "", "", null, false,
|
||||
false, 0, "", null, 0, null
|
||||
);
|
||||
|
||||
// Assert
|
||||
address.LastSeen.Should().BeNull();
|
||||
address.EditDate.Should().BeNull();
|
||||
address.ExtendedData.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_ReturnsIpAddress()
|
||||
{
|
||||
// Arrange
|
||||
var address = new Address(
|
||||
1, 10, "192.168.1.50", false, "Test", "host.local", "", "",
|
||||
0, 0, "", "", "", null, false,
|
||||
false, 0, "", null, 0, null
|
||||
);
|
||||
|
||||
// Act
|
||||
var result = address.ToString();
|
||||
|
||||
// Assert
|
||||
result.Should().Be("192.168.1.50");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("10.0.0.1")]
|
||||
[InlineData("172.16.0.100")]
|
||||
[InlineData("192.168.255.255")]
|
||||
[InlineData("2001:db8::1")]
|
||||
public void ToString_ReturnsCorrectIp_ForVariousAddresses(string expectedIp)
|
||||
{
|
||||
// Arrange
|
||||
var address = new Address(
|
||||
1, 1, expectedIp, false, "", "", "", "",
|
||||
0, 0, "", "", "", null, false,
|
||||
false, 0, "", null, 0, null
|
||||
);
|
||||
|
||||
// Act & Assert
|
||||
address.ToString().Should().Be(expectedIp);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Record_Equality_WorksCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var address1 = new Address(
|
||||
1, 10, "192.168.1.1", false, "Test", "host", "", "",
|
||||
0, 0, "", "", "", null, false,
|
||||
false, 0, "", null, 0, null
|
||||
);
|
||||
|
||||
var address2 = new Address(
|
||||
1, 10, "192.168.1.1", false, "Test", "host", "", "",
|
||||
0, 0, "", "", "", null, false,
|
||||
false, 0, "", null, 0, null
|
||||
);
|
||||
|
||||
// Assert
|
||||
address1.Should().Be(address2);
|
||||
}
|
||||
}
|
||||
43
classlib.tests/Models/DomainTests.cs
Normal file
43
classlib.tests/Models/DomainTests.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class DomainTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
var name = "Default";
|
||||
var description = "Default L2 domain";
|
||||
var sections = "1;2;3";
|
||||
|
||||
// Act
|
||||
var domain = new Domain(id, name, description, sections);
|
||||
|
||||
// Assert
|
||||
domain.Id.Should().Be(id);
|
||||
domain.Name.Should().Be(name);
|
||||
domain.Description.Should().Be(description);
|
||||
domain.Sections.Should().Be(sections);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Default")]
|
||||
[InlineData("Datacenter1")]
|
||||
[InlineData("Branch_Office")]
|
||||
public void ToString_ReturnsDomainName(string domainName)
|
||||
{
|
||||
// Arrange
|
||||
var domain = new Domain(1, domainName, "", "");
|
||||
|
||||
// Act
|
||||
var result = domain.ToString();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(domainName);
|
||||
}
|
||||
}
|
||||
104
classlib.tests/Models/NameserverTests.cs
Normal file
104
classlib.tests/Models/NameserverTests.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class NameserverTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
var name = "Google DNS";
|
||||
var nameServers = "8.8.8.8;8.8.4.4";
|
||||
var description = "Google Public DNS";
|
||||
var permissions = "{\"3\":\"2\"}";
|
||||
var editDate = new DateTime(2026, 1, 10);
|
||||
|
||||
// Act
|
||||
var nameserver = new Nameserver(id, name, nameServers, description, permissions, editDate);
|
||||
|
||||
// Assert
|
||||
nameserver.Id.Should().Be(id);
|
||||
nameserver.Name.Should().Be(name);
|
||||
nameserver.Description.Should().Be(description);
|
||||
nameserver.Permissions.Should().Be(permissions);
|
||||
nameserver.EditDate.Should().Be(editDate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_ParsesNameservers_BySemicolon()
|
||||
{
|
||||
// Arrange
|
||||
var nameServersString = "8.8.8.8;8.8.4.4;1.1.1.1";
|
||||
|
||||
// Act
|
||||
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
|
||||
|
||||
// Assert
|
||||
nameserver.NameServers.Should().HaveCount(3);
|
||||
nameserver.NameServers.Should().ContainInOrder("8.8.8.8", "8.8.4.4", "1.1.1.1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithSingleNameserver_ReturnsArrayWithOneElement()
|
||||
{
|
||||
// Arrange
|
||||
var nameServersString = "8.8.8.8";
|
||||
|
||||
// Act
|
||||
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
|
||||
|
||||
// Assert
|
||||
nameserver.NameServers.Should().HaveCount(1);
|
||||
nameserver.NameServers[0].Should().Be("8.8.8.8");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithEmptyNameservers_ReturnsEmptyArray()
|
||||
{
|
||||
// Arrange
|
||||
var nameServersString = "";
|
||||
|
||||
// Act
|
||||
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
|
||||
|
||||
// Assert - Empty entries are excluded
|
||||
nameserver.NameServers.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithNullEditDate_SetsNull()
|
||||
{
|
||||
// Act
|
||||
var nameserver = new Nameserver(1, "Test", "8.8.8.8", "", "", null);
|
||||
|
||||
// Assert
|
||||
nameserver.EditDate.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithSemicolonOnlyString_ReturnsEmptyArray()
|
||||
{
|
||||
// Arrange - edge case with just semicolons
|
||||
var nameServersString = ";;;";
|
||||
|
||||
// Act
|
||||
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
|
||||
|
||||
// Assert
|
||||
nameserver.NameServers.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_ReturnsName()
|
||||
{
|
||||
// Arrange
|
||||
var nameserver = new Nameserver(1, "Google DNS", "8.8.8.8", "", "", null);
|
||||
|
||||
// Act & Assert
|
||||
nameserver.ToString().Should().Be("Google DNS");
|
||||
}
|
||||
}
|
||||
77
classlib.tests/Models/SectionTests.cs
Normal file
77
classlib.tests/Models/SectionTests.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class SectionTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
var name = "Production";
|
||||
var description = "Production networks section";
|
||||
var masterSectionId = 0;
|
||||
var permissions = "{\"3\":\"2\"}";
|
||||
var strictMode = true;
|
||||
var subnetOrdering = "subnet,asc";
|
||||
var order = 1;
|
||||
var editDate = new DateTime(2026, 1, 5);
|
||||
var showSubnet = true;
|
||||
var showVlan = true;
|
||||
var showVRF = false;
|
||||
var showSupernetOnly = false;
|
||||
var dnsId = 1;
|
||||
|
||||
// Act
|
||||
var section = new Section(
|
||||
id, name, description, masterSectionId, permissions, strictMode,
|
||||
subnetOrdering, order, editDate, showSubnet, showVlan, showVRF,
|
||||
showSupernetOnly, dnsId
|
||||
);
|
||||
|
||||
// Assert
|
||||
section.Id.Should().Be(id);
|
||||
section.Name.Should().Be(name);
|
||||
section.Description.Should().Be(description);
|
||||
section.MasterSectionId.Should().Be(masterSectionId);
|
||||
section.Permissions.Should().Be(permissions);
|
||||
section.StrictMode.Should().Be(strictMode);
|
||||
section.SubnetOrdering.Should().Be(subnetOrdering);
|
||||
section.Order.Should().Be(order);
|
||||
section.EditDate.Should().Be(editDate);
|
||||
section.ShowSubnet.Should().Be(showSubnet);
|
||||
section.ShowVlan.Should().Be(showVlan);
|
||||
section.ShowVRF.Should().Be(showVRF);
|
||||
section.ShowSupernetOnly.Should().Be(showSupernetOnly);
|
||||
section.DNSId.Should().Be(dnsId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Production")]
|
||||
[InlineData("Development")]
|
||||
[InlineData("DMZ")]
|
||||
public void ToString_ReturnsSectionName(string sectionName)
|
||||
{
|
||||
// Arrange
|
||||
var section = new Section(1, sectionName, "", 0, "", false, "", 0, null, false, false, false, false, 0);
|
||||
|
||||
// Act
|
||||
var result = section.ToString();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(sectionName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithNullEditDate_SetsNull()
|
||||
{
|
||||
// Act
|
||||
var section = new Section(1, "Test", "", 0, "", false, "", 0, null, false, false, false, false, 0);
|
||||
|
||||
// Assert
|
||||
section.EditDate.Should().BeNull();
|
||||
}
|
||||
}
|
||||
90
classlib.tests/Models/SessionTests.cs
Normal file
90
classlib.tests/Models/SessionTests.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class SessionTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_WithCredentialsAuth_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var authType = AuthType.Credentials;
|
||||
var token = "test-token-123";
|
||||
var appId = "myApp";
|
||||
var url = "https://ipam.example.com";
|
||||
var expires = new DateTime(2026, 12, 31, 23, 59, 59);
|
||||
var credentials = new object(); // Mock credentials
|
||||
|
||||
// Act
|
||||
var session = new Session(authType, token, appId, url, expires, credentials);
|
||||
|
||||
// Assert
|
||||
session.AuthType.Should().Be(AuthType.Credentials);
|
||||
session.Token.Should().Be(token);
|
||||
session.AppID.Should().Be(appId);
|
||||
session.URL.Should().Be(url);
|
||||
session.Expires.Should().Be(expires);
|
||||
session.Credentials.Should().BeSameAs(credentials);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithTokenAuth_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var authType = AuthType.Token;
|
||||
var token = "static-api-token";
|
||||
var appId = "apiApp";
|
||||
var url = "https://ipam.test.com";
|
||||
|
||||
// Act
|
||||
var session = new Session(authType, token, appId, url, null, null);
|
||||
|
||||
// Assert
|
||||
session.AuthType.Should().Be(AuthType.Token);
|
||||
session.Token.Should().Be(token);
|
||||
session.AppID.Should().Be(appId);
|
||||
session.URL.Should().Be(url);
|
||||
session.Expires.Should().BeNull();
|
||||
session.Credentials.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Token_CanBeModified()
|
||||
{
|
||||
// Arrange
|
||||
var session = new Session(AuthType.Credentials, "old-token", "app", "https://test.com", null, null);
|
||||
|
||||
// Act
|
||||
session.Token = "new-token";
|
||||
|
||||
// Assert
|
||||
session.Token.Should().Be("new-token");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Expires_CanBeModified()
|
||||
{
|
||||
// Arrange
|
||||
var session = new Session(AuthType.Credentials, "token", "app", "https://test.com", null, null);
|
||||
var newExpiry = new DateTime(2027, 1, 1);
|
||||
|
||||
// Act
|
||||
session.Expires = newExpiry;
|
||||
|
||||
// Assert
|
||||
session.Expires.Should().Be(newExpiry);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Record_Equality_WorksForSameValues()
|
||||
{
|
||||
// Arrange
|
||||
var session1 = new Session(AuthType.Token, "token", "app", "https://test.com", null, null);
|
||||
var session2 = new Session(AuthType.Token, "token", "app", "https://test.com", null, null);
|
||||
|
||||
// Assert - Records use value equality
|
||||
session1.Should().Be(session2);
|
||||
}
|
||||
}
|
||||
157
classlib.tests/Models/SubnetworkTests.cs
Normal file
157
classlib.tests/Models/SubnetworkTests.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class SubnetworkTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
var subnet = "192.168.1.0";
|
||||
var mask = 24;
|
||||
var sectionId = 5;
|
||||
var description = "Production network";
|
||||
var linkedSubnet = "linked-123";
|
||||
var firewallObject = "FW_PROD";
|
||||
var vrfId = 2;
|
||||
var masterSubnetId = 0;
|
||||
var allowRequests = true;
|
||||
var vlanId = 100;
|
||||
var showName = true;
|
||||
var deviceId = 10;
|
||||
var permissions = "rw";
|
||||
var pingSubnet = true;
|
||||
var discoverSubnet = false;
|
||||
var resolveDNS = true;
|
||||
var dnsRecursive = false;
|
||||
var dnsRecords = true;
|
||||
var nameserverId = 3;
|
||||
var scanAgent = false;
|
||||
var isFolder = false;
|
||||
var isFull = false;
|
||||
var isPool = true;
|
||||
var tagId = 1;
|
||||
var threshold = 80;
|
||||
var locationId = 4;
|
||||
var editDate = new DateTime(2026, 1, 10);
|
||||
var lastScan = new DateTime(2026, 1, 9);
|
||||
var lastDiscovery = new DateTime(2026, 1, 8);
|
||||
var calculation = new { maxhosts = 254 };
|
||||
var customFields = new Dictionary<string, object> { { "custom_env", "prod" } };
|
||||
|
||||
// Act
|
||||
var subnetwork = new Subnetwork(
|
||||
id, subnet, mask, sectionId, description, linkedSubnet, firewallObject,
|
||||
vrfId, masterSubnetId, allowRequests, vlanId, showName, deviceId,
|
||||
permissions, pingSubnet, discoverSubnet, resolveDNS, dnsRecursive,
|
||||
dnsRecords, nameserverId, scanAgent, isFolder, isFull, isPool,
|
||||
tagId, threshold, locationId, editDate, lastScan, lastDiscovery,
|
||||
calculation, customFields
|
||||
);
|
||||
|
||||
// Assert
|
||||
subnetwork.Id.Should().Be(id);
|
||||
subnetwork.Subnet.Should().Be(subnet);
|
||||
subnetwork.Mask.Should().Be(mask);
|
||||
subnetwork.SectionId.Should().Be(sectionId);
|
||||
subnetwork.Description.Should().Be(description);
|
||||
subnetwork.LinkedSubnet.Should().Be(linkedSubnet);
|
||||
subnetwork.FirewallAddressObject.Should().Be(firewallObject);
|
||||
subnetwork.VrfId.Should().Be(vrfId);
|
||||
subnetwork.MasterSubnetId.Should().Be(masterSubnetId);
|
||||
subnetwork.AllowRequests.Should().Be(allowRequests);
|
||||
subnetwork.VlanId.Should().Be(vlanId);
|
||||
subnetwork.ShowName.Should().Be(showName);
|
||||
subnetwork.DeviceId.Should().Be(deviceId);
|
||||
subnetwork.Permissions.Should().Be(permissions);
|
||||
subnetwork.PingSubnet.Should().Be(pingSubnet);
|
||||
subnetwork.DiscoverSubnet.Should().Be(discoverSubnet);
|
||||
subnetwork.ResolveDNS.Should().Be(resolveDNS);
|
||||
subnetwork.DNSRecursive.Should().Be(dnsRecursive);
|
||||
subnetwork.DNSRecords.Should().Be(dnsRecords);
|
||||
subnetwork.NameserverId.Should().Be(nameserverId);
|
||||
subnetwork.ScanAgent.Should().Be(scanAgent);
|
||||
subnetwork.IsFolder.Should().Be(isFolder);
|
||||
subnetwork.IsFull.Should().Be(isFull);
|
||||
subnetwork.IsPool.Should().Be(isPool);
|
||||
subnetwork.TagId.Should().Be(tagId);
|
||||
subnetwork.Threshold.Should().Be(threshold);
|
||||
subnetwork.LocationId.Should().Be(locationId);
|
||||
subnetwork.EditDate.Should().Be(editDate);
|
||||
subnetwork.LastScan.Should().Be(lastScan);
|
||||
subnetwork.LastDiscovery.Should().Be(lastDiscovery);
|
||||
subnetwork.Calculation.Should().BeEquivalentTo(calculation);
|
||||
subnetwork.ExtendedData.Should().BeEquivalentTo(customFields);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("192.168.1.0", 24, "192.168.1.0/24")]
|
||||
[InlineData("10.0.0.0", 8, "10.0.0.0/8")]
|
||||
[InlineData("172.16.0.0", 16, "172.16.0.0/16")]
|
||||
[InlineData("192.168.100.0", 30, "192.168.100.0/30")]
|
||||
public void CIDR_ReturnsCidrNotation(string subnet, int mask, string expectedCidr)
|
||||
{
|
||||
// Arrange
|
||||
var subnetwork = CreateSubnetwork(subnet, mask);
|
||||
|
||||
// Act
|
||||
var result = subnetwork.CIDR;
|
||||
|
||||
// Assert
|
||||
result.Should().Be(expectedCidr);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_ReturnsCidrNotation()
|
||||
{
|
||||
// Arrange
|
||||
var subnetwork = CreateSubnetwork("10.10.0.0", 16);
|
||||
|
||||
// Act
|
||||
var result = subnetwork.ToString();
|
||||
|
||||
// Assert
|
||||
result.Should().Be("10.10.0.0/16");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToString_EqualsCIDRProperty()
|
||||
{
|
||||
// Arrange
|
||||
var subnetwork = CreateSubnetwork("172.20.0.0", 12);
|
||||
|
||||
// Act & Assert
|
||||
subnetwork.ToString().Should().Be(subnetwork.CIDR);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Record_Equality_WorksCorrectly()
|
||||
{
|
||||
// Arrange - use same calculation object for equality comparison
|
||||
var calculation = new { maxhosts = 254 };
|
||||
var subnet1 = CreateSubnetwork("192.168.1.0", 24, calculation);
|
||||
var subnet2 = CreateSubnetwork("192.168.1.0", 24, calculation);
|
||||
|
||||
// Assert - records use value equality (except for the Calculation object reference)
|
||||
subnet1.Id.Should().Be(subnet2.Id);
|
||||
subnet1.Subnet.Should().Be(subnet2.Subnet);
|
||||
subnet1.Mask.Should().Be(subnet2.Mask);
|
||||
subnet1.CIDR.Should().Be(subnet2.CIDR);
|
||||
}
|
||||
|
||||
private static Subnetwork CreateSubnetwork(string subnet, int mask, object? calculation = null)
|
||||
{
|
||||
return new Subnetwork(
|
||||
1, subnet, mask, 1, "", "", "",
|
||||
0, 0, false, 0, false, 0,
|
||||
"", false, false, false, false,
|
||||
false, 0, false, false, false, false,
|
||||
0, 0, 0, null, null, null,
|
||||
calculation ?? new object(), null
|
||||
);
|
||||
}
|
||||
}
|
||||
63
classlib.tests/Models/TagTests.cs
Normal file
63
classlib.tests/Models/TagTests.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class TagTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
var type = "Used";
|
||||
var showTag = true;
|
||||
var bgColor = "#5cb85c";
|
||||
var fgColor = "#ffffff";
|
||||
var compress = "Yes";
|
||||
var locked = "No";
|
||||
var updateTag = true;
|
||||
|
||||
// Act
|
||||
var tag = new Tag(id, type, showTag, bgColor, fgColor, compress, locked, updateTag);
|
||||
|
||||
// Assert
|
||||
tag.Id.Should().Be(id);
|
||||
tag.Type.Should().Be(type);
|
||||
tag.ShowTag.Should().Be(showTag);
|
||||
tag.BackgroundColor.Should().Be(bgColor);
|
||||
tag.ForegroundColor.Should().Be(fgColor);
|
||||
tag.Compress.Should().Be(compress);
|
||||
tag.Locked.Should().Be(locked);
|
||||
tag.UpdateTag.Should().Be(updateTag);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Used")]
|
||||
[InlineData("Available")]
|
||||
[InlineData("Reserved")]
|
||||
[InlineData("DHCP")]
|
||||
public void ToString_ReturnsTagType(string tagType)
|
||||
{
|
||||
// Arrange
|
||||
var tag = new Tag(1, tagType, false, "", "", "No", "No", false);
|
||||
|
||||
// Act
|
||||
var result = tag.ToString();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(tagType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Record_Equality_WorksCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
var tag1 = new Tag(1, "Used", true, "#fff", "#000", "Yes", "No", false);
|
||||
var tag2 = new Tag(1, "Used", true, "#fff", "#000", "Yes", "No", false);
|
||||
|
||||
// Assert
|
||||
tag1.Should().Be(tag2);
|
||||
}
|
||||
}
|
||||
76
classlib.tests/Models/VlanTests.cs
Normal file
76
classlib.tests/Models/VlanTests.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class VlanTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var vlanId = 100;
|
||||
var domainId = 1;
|
||||
var name = "Production VLAN";
|
||||
var number = 100;
|
||||
var description = "Production network VLAN";
|
||||
var editDate = new DateTime(2026, 1, 15);
|
||||
var customerId = 50;
|
||||
var customFields = new Dictionary<string, object> { { "custom_location", "DC1" } };
|
||||
|
||||
// Act
|
||||
var vlan = new Vlan(vlanId, domainId, name, number, description, editDate, customerId, customFields);
|
||||
|
||||
// Assert
|
||||
vlan.Id.Should().Be(vlanId);
|
||||
vlan.VlanId.Should().Be(vlanId);
|
||||
vlan.DomainId.Should().Be(domainId);
|
||||
vlan.Name.Should().Be(name);
|
||||
vlan.Number.Should().Be(number);
|
||||
vlan.Description.Should().Be(description);
|
||||
vlan.EditDate.Should().Be(editDate);
|
||||
vlan.CustomerId.Should().Be(customerId);
|
||||
vlan.ExtendedData.Should().BeEquivalentTo(customFields);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Id_And_VlanId_AreSameValue()
|
||||
{
|
||||
// Arrange
|
||||
var vlanId = 200;
|
||||
|
||||
// Act
|
||||
var vlan = new Vlan(vlanId, 1, "Test", 200, "", null, 0, null);
|
||||
|
||||
// Assert
|
||||
vlan.Id.Should().Be(vlan.VlanId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1)]
|
||||
[InlineData(100)]
|
||||
[InlineData(4094)]
|
||||
public void ToString_ReturnsVlanNumber(int vlanNumber)
|
||||
{
|
||||
// Arrange
|
||||
var vlan = new Vlan(1, 1, "Test", vlanNumber, "", null, 0, null);
|
||||
|
||||
// Act
|
||||
var result = vlan.ToString();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(vlanNumber.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithNullOptionalFields_SetsNullValues()
|
||||
{
|
||||
// Act
|
||||
var vlan = new Vlan(1, 1, "Test", 10, "", null, 0, null);
|
||||
|
||||
// Assert
|
||||
vlan.EditDate.Should().BeNull();
|
||||
vlan.ExtendedData.Should().BeNull();
|
||||
}
|
||||
}
|
||||
60
classlib.tests/Models/VrfTests.cs
Normal file
60
classlib.tests/Models/VrfTests.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace PS.IPAM.Tests.Models;
|
||||
|
||||
using FluentAssertions;
|
||||
using PS.IPAM;
|
||||
using Xunit;
|
||||
|
||||
public class VrfTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_SetsAllProperties()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
var name = "VRF_PROD";
|
||||
var rd = "65000:100";
|
||||
var description = "Production VRF";
|
||||
var sections = "1;2;3";
|
||||
var editDate = new DateTime(2026, 1, 10);
|
||||
var customFields = new Dictionary<string, object> { { "custom_tenant", "CustomerA" } };
|
||||
|
||||
// Act
|
||||
var vrf = new Vrf(id, name, rd, description, sections, editDate, customFields);
|
||||
|
||||
// Assert
|
||||
vrf.Id.Should().Be(id);
|
||||
vrf.Name.Should().Be(name);
|
||||
vrf.RouteDistinguisher.Should().Be(rd);
|
||||
vrf.Description.Should().Be(description);
|
||||
vrf.Sections.Should().Be(sections);
|
||||
vrf.EditDate.Should().Be(editDate);
|
||||
vrf.ExtendedData.Should().BeEquivalentTo(customFields);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("VRF_DEFAULT")]
|
||||
[InlineData("Production_VRF")]
|
||||
[InlineData("CUSTOMER_A")]
|
||||
public void ToString_ReturnsVrfName(string vrfName)
|
||||
{
|
||||
// Arrange
|
||||
var vrf = new Vrf(1, vrfName, "65000:1", "", "", null, null);
|
||||
|
||||
// Act
|
||||
var result = vrf.ToString();
|
||||
|
||||
// Assert
|
||||
result.Should().Be(vrfName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_WithNullOptionalFields_SetsNullValues()
|
||||
{
|
||||
// Act
|
||||
var vrf = new Vrf(1, "Test", "65000:1", "", "", null, null);
|
||||
|
||||
// Assert
|
||||
vrf.EditDate.Should().BeNull();
|
||||
vrf.ExtendedData.Should().BeNull();
|
||||
}
|
||||
}
|
||||
32
classlib.tests/TestCollections.cs
Normal file
32
classlib.tests/TestCollections.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace PS.IPAM.Tests;
|
||||
|
||||
using Xunit;
|
||||
|
||||
/// <summary>
|
||||
/// Collection definition for tests that share static state (SessionManager, RequestHelper.TestHttpHandler).
|
||||
/// Tests in this collection will run sequentially, not in parallel.
|
||||
/// </summary>
|
||||
[CollectionDefinition("Sequential")]
|
||||
public class SequentialCollection : ICollectionFixture<SequentialTestFixture>
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fixture for sequential test collection.
|
||||
/// </summary>
|
||||
public class SequentialTestFixture : IDisposable
|
||||
{
|
||||
public SequentialTestFixture()
|
||||
{
|
||||
// Clean up before tests
|
||||
PS.IPAM.Helpers.SessionManager.CloseSession();
|
||||
PS.IPAM.Helpers.RequestHelper.TestHttpHandler = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Clean up after tests
|
||||
PS.IPAM.Helpers.SessionManager.CloseSession();
|
||||
PS.IPAM.Helpers.RequestHelper.TestHttpHandler = null;
|
||||
}
|
||||
}
|
||||
33
classlib.tests/classlib.tests.csproj
Normal file
33
classlib.tests/classlib.tests.csproj
Normal file
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<RootNamespace>PS.IPAM.Tests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.6.4" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Moq" Version="4.20.70" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\classlib\classlib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
60
classlib/Cmdlets/AssignTagCmdlet.cs
Normal file
60
classlib/Cmdlets/AssignTagCmdlet.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Assigns a tag to an address in phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet("Assign", "Tag", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(Address))]
|
||||
public class AssignTagCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
HelpMessage = "The address to assign the tag to.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Address? AddressObject { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
Position = 1,
|
||||
HelpMessage = "The tag to assign.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Tag? Tag { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var identifiers = new[] { AddressObject!.Id.ToString() };
|
||||
var body = new Dictionary<string, object>
|
||||
{
|
||||
["tag"] = Tag!.Id
|
||||
};
|
||||
|
||||
if (ShouldProcess($"Address {AddressObject.Ip}", $"Assign tag '{Tag.Type}'"))
|
||||
{
|
||||
RequestHelper.InvokeRequest(
|
||||
"PATCH", ApiController.Addresses, null, null, body, identifiers
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
// Return the updated address
|
||||
var address = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Addresses, ModelType.Address, null, null, identifiers
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(address);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "AssignTagError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
114
classlib/Cmdlets/BaseCmdlet.cs
Normal file
114
classlib/Cmdlets/BaseCmdlet.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all PS.IPAM cmdlets providing common functionality.
|
||||
/// </summary>
|
||||
public abstract class BaseCmdlet : PSCmdlet
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes the result to the pipeline, handling both single objects and collections.
|
||||
/// </summary>
|
||||
/// <param name="result">The result to write to the pipeline.</param>
|
||||
protected void WriteResult(object? result)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (result is IEnumerable enumerable && result is not string)
|
||||
{
|
||||
foreach (var item in enumerable)
|
||||
{
|
||||
WriteObject(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteObject(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts custom fields from various formats to a dictionary.
|
||||
/// </summary>
|
||||
/// <param name="customFields">The custom fields object to convert.</param>
|
||||
/// <returns>A dictionary of custom field names and values.</returns>
|
||||
protected static Dictionary<string, object> ConvertCustomFields(object? customFields)
|
||||
{
|
||||
if (customFields == null)
|
||||
{
|
||||
return new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
if (customFields is PSObject psobj)
|
||||
{
|
||||
var dict = new Dictionary<string, object>();
|
||||
foreach (var prop in psobj.Properties)
|
||||
{
|
||||
dict[prop.Name] = prop.Value ?? string.Empty;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
if (customFields is Dictionary<string, object> dictObj)
|
||||
{
|
||||
return dictObj;
|
||||
}
|
||||
|
||||
if (customFields is IDictionary genericDict)
|
||||
{
|
||||
var result = new Dictionary<string, object>();
|
||||
foreach (DictionaryEntry entry in genericDict)
|
||||
{
|
||||
result[entry.Key?.ToString() ?? string.Empty] = entry.Value ?? string.Empty;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes an async operation synchronously and handles errors.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The return type of the operation.</typeparam>
|
||||
/// <param name="operation">The async operation to execute.</param>
|
||||
/// <param name="errorId">The error ID for error reporting.</param>
|
||||
/// <returns>The result of the operation, or default if an error occurred.</returns>
|
||||
protected T? ExecuteAsync<T>(Func<System.Threading.Tasks.Task<T>> operation, string errorId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return operation().GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, errorId, ErrorCategory.InvalidOperation, null));
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes an async operation synchronously and handles errors.
|
||||
/// </summary>
|
||||
/// <param name="operation">The async operation to execute.</param>
|
||||
/// <param name="errorId">The error ID for error reporting.</param>
|
||||
protected void ExecuteAsync(Func<System.Threading.Tasks.Task> operation, string errorId)
|
||||
{
|
||||
try
|
||||
{
|
||||
operation().GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, errorId, ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
17
classlib/Cmdlets/CloseSessionCmdlet.cs
Normal file
17
classlib/Cmdlets/CloseSessionCmdlet.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Closes the current phpIPAM API session.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Close, "Session")]
|
||||
public class CloseSessionCmdlet : BaseCmdlet
|
||||
{
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
SessionManager.CloseSession();
|
||||
WriteVerbose("Session closed successfully.");
|
||||
}
|
||||
}
|
||||
169
classlib/Cmdlets/GetAddressCmdlet.cs
Normal file
169
classlib/Cmdlets/GetAddressCmdlet.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using System.Net;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves IP address entries from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Address", DefaultParameterSetName = "ByID")]
|
||||
[OutputType(typeof(Address))]
|
||||
public class GetAddressCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The address ID to retrieve.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByIP",
|
||||
HelpMessage = "The IP address to search for.")]
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 1,
|
||||
ParameterSetName = "BySubnetId")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public IPAddress? IP { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByHostName",
|
||||
HelpMessage = "The hostname to search for.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? HostName { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByHostBase",
|
||||
HelpMessage = "The hostname base pattern to search for.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? HostBase { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByTag",
|
||||
HelpMessage = "The tag ID to filter addresses by.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? TagId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetId",
|
||||
HelpMessage = "The subnet ID to get addresses from.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? SubnetId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetCIDR",
|
||||
HelpMessage = "The subnet in CIDR notation to get addresses from.")]
|
||||
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? SubnetCIDR { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var controller = ApiController.Addresses;
|
||||
var identifiers = new List<string>();
|
||||
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
case "ByID":
|
||||
identifiers.Add(Id.ToString());
|
||||
break;
|
||||
|
||||
case "ByIP":
|
||||
identifiers.Add("search");
|
||||
identifiers.Add(IP!.ToString());
|
||||
break;
|
||||
|
||||
case "ByHostName":
|
||||
identifiers.Add("search_hostname");
|
||||
identifiers.Add(HostName!);
|
||||
break;
|
||||
|
||||
case "ByHostBase":
|
||||
identifiers.Add("search_hostbase");
|
||||
identifiers.Add(HostBase!);
|
||||
break;
|
||||
|
||||
case "ByTag":
|
||||
identifiers.Add("tags");
|
||||
identifiers.Add(TagId!.Value.ToString());
|
||||
identifiers.Add("addresses");
|
||||
break;
|
||||
|
||||
case "BySubnetId":
|
||||
if (IP != null)
|
||||
{
|
||||
identifiers.Add(IP.ToString());
|
||||
identifiers.Add(SubnetId!.Value.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
controller = ApiController.Subnets;
|
||||
identifiers.Add(SubnetId!.Value.ToString());
|
||||
identifiers.Add("addresses");
|
||||
}
|
||||
break;
|
||||
|
||||
case "BySubnetCIDR":
|
||||
controller = ApiController.Subnets;
|
||||
var subnet = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
|
||||
new[] { "cidr", SubnetCIDR! }
|
||||
).GetAwaiter().GetResult() as Subnetwork;
|
||||
|
||||
if (subnet == null)
|
||||
{
|
||||
throw new ItemNotFoundException($"Subnet '{SubnetCIDR}' not found.");
|
||||
}
|
||||
|
||||
identifiers.Add(subnet.Id.ToString());
|
||||
identifiers.Add("addresses");
|
||||
break;
|
||||
}
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", controller, ModelType.Address, null, null, identifiers.ToArray()
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetAddressError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
90
classlib/Cmdlets/GetFirstFreeIPCmdlet.cs
Normal file
90
classlib/Cmdlets/GetFirstFreeIPCmdlet.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first available IP address in a subnet.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "FirstFreeIP", DefaultParameterSetName = "ByID")]
|
||||
public class GetFirstFreeIPCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByCIDR",
|
||||
HelpMessage = "The subnet in CIDR notation.")]
|
||||
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? CIDR { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The subnet ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetObject",
|
||||
HelpMessage = "The subnet object.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Subnetwork? SubnetObject { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var subnetId = GetSubnetId();
|
||||
var identifiers = new List<string> { subnetId.ToString(), "first_free" };
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Subnets, null, null, null, identifiers.ToArray()
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
WriteObject(new { Ip = result.ToString() });
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetFirstFreeIPError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
|
||||
private int GetSubnetId()
|
||||
{
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
case "ByCIDR":
|
||||
var subnet = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
|
||||
new[] { "cidr", CIDR! }
|
||||
).GetAwaiter().GetResult() as Subnetwork;
|
||||
|
||||
if (subnet == null)
|
||||
{
|
||||
throw new ItemNotFoundException($"Subnet '{CIDR}' not found.");
|
||||
}
|
||||
return subnet.Id;
|
||||
|
||||
case "BySubnetObject":
|
||||
return SubnetObject!.Id;
|
||||
|
||||
default:
|
||||
return Id!.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
classlib/Cmdlets/GetL2DomainCmdlet.cs
Normal file
48
classlib/Cmdlets/GetL2DomainCmdlet.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves L2 domain information from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "L2Domain", DefaultParameterSetName = "ByID")]
|
||||
[OutputType(typeof(Domain))]
|
||||
public class GetL2DomainCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The L2 domain ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var identifiers = new List<string>();
|
||||
|
||||
if (Id.HasValue)
|
||||
{
|
||||
identifiers.Add(Id.Value.ToString());
|
||||
}
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.L2Domains, ModelType.Domain, null, null,
|
||||
identifiers.Count > 0 ? identifiers.ToArray() : null
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetL2DomainError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
48
classlib/Cmdlets/GetNameserverCmdlet.cs
Normal file
48
classlib/Cmdlets/GetNameserverCmdlet.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves nameserver information from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Nameserver", DefaultParameterSetName = "NoParams")]
|
||||
[OutputType(typeof(Nameserver))]
|
||||
public class GetNameserverCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The nameserver ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var identifiers = new List<string>();
|
||||
|
||||
if (Id.HasValue)
|
||||
{
|
||||
identifiers.Add(Id.Value.ToString());
|
||||
}
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Tools, ModelType.Nameserver, ApiSubController.Nameservers,
|
||||
null, identifiers.Count > 0 ? identifiers.ToArray() : null
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetNameserverError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
153
classlib/Cmdlets/GetPermissionsCmdlet.cs
Normal file
153
classlib/Cmdlets/GetPermissionsCmdlet.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using System.Net;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves permission information from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Permissions")]
|
||||
public class GetPermissionsCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The address ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByIP",
|
||||
HelpMessage = "The IP address to search for.")]
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 1,
|
||||
ParameterSetName = "BySubnetId")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public IPAddress? IP { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByHostName",
|
||||
HelpMessage = "The hostname to search for.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? HostName { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByTag",
|
||||
HelpMessage = "The tag ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? TagId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetId",
|
||||
HelpMessage = "The subnet ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? SubnetId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetCIDR",
|
||||
HelpMessage = "The subnet in CIDR notation.")]
|
||||
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? SubnetCIDR { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var controller = ApiController.Addresses;
|
||||
var identifiers = new List<string>();
|
||||
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
case "ByID":
|
||||
identifiers.Add(Id!);
|
||||
break;
|
||||
|
||||
case "ByIP":
|
||||
identifiers.Add("search");
|
||||
identifiers.Add(IP!.ToString());
|
||||
break;
|
||||
|
||||
case "ByHostName":
|
||||
identifiers.Add("search_hostname");
|
||||
identifiers.Add(HostName!);
|
||||
break;
|
||||
|
||||
case "ByTag":
|
||||
identifiers.Add("tags");
|
||||
identifiers.Add(TagId!);
|
||||
identifiers.Add("addresses");
|
||||
break;
|
||||
|
||||
case "BySubnetId":
|
||||
if (IP != null)
|
||||
{
|
||||
identifiers.Add(IP.ToString());
|
||||
identifiers.Add(SubnetId!);
|
||||
}
|
||||
else
|
||||
{
|
||||
controller = ApiController.Subnets;
|
||||
identifiers.Add(SubnetId!);
|
||||
identifiers.Add("addresses");
|
||||
}
|
||||
break;
|
||||
|
||||
case "BySubnetCIDR":
|
||||
controller = ApiController.Subnets;
|
||||
var subnet = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
|
||||
new[] { "cidr", SubnetCIDR! }
|
||||
).GetAwaiter().GetResult() as Subnetwork;
|
||||
|
||||
if (subnet == null)
|
||||
{
|
||||
throw new ItemNotFoundException($"Subnet '{SubnetCIDR}' not found.");
|
||||
}
|
||||
|
||||
identifiers.Add(subnet.Id.ToString());
|
||||
identifiers.Add("addresses");
|
||||
break;
|
||||
}
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", controller, null, null, null, identifiers.ToArray()
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetPermissionsError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
60
classlib/Cmdlets/GetSectionCmdlet.cs
Normal file
60
classlib/Cmdlets/GetSectionCmdlet.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves section information from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Section", DefaultParameterSetName = "NoParams")]
|
||||
[OutputType(typeof(Section))]
|
||||
public class GetSectionCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The section ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByName",
|
||||
HelpMessage = "The section name.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? Name { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var identifiers = new List<string>();
|
||||
|
||||
if (ParameterSetName == "ByID" && Id.HasValue)
|
||||
{
|
||||
identifiers.Add(Id.Value.ToString());
|
||||
}
|
||||
else if (ParameterSetName == "ByName")
|
||||
{
|
||||
identifiers.Add(Name!);
|
||||
}
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Sections, ModelType.Section, null, null,
|
||||
identifiers.Count > 0 ? identifiers.ToArray() : null
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetSectionError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
277
classlib/Cmdlets/GetSubnetCmdlet.cs
Normal file
277
classlib/Cmdlets/GetSubnetCmdlet.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves subnet information from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Subnet", DefaultParameterSetName = "NoParams")]
|
||||
[OutputType(typeof(Subnetwork))]
|
||||
public class GetSubnetCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByCIDR",
|
||||
HelpMessage = "The subnet in CIDR notation (e.g., 192.168.1.0/24).")]
|
||||
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? CIDR { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The subnet ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySectionId",
|
||||
HelpMessage = "The section ID to get subnets from.")]
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 2,
|
||||
ParameterSetName = "ByVlanNumber")]
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 1,
|
||||
ParameterSetName = "ByVlanId")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? SectionId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySectionName",
|
||||
HelpMessage = "The section name to get subnets from.")]
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 3,
|
||||
ParameterSetName = "ByVlanNumber")]
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 2,
|
||||
ParameterSetName = "ByVlanId")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? SectionName { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByVrfId",
|
||||
HelpMessage = "The VRF ID to get subnets from.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? VrfId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByVlanId",
|
||||
HelpMessage = "The VLAN ID to get subnets from.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? VlanId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByVlanNumber",
|
||||
HelpMessage = "The VLAN number to get subnets from.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? VlanNumber { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 1,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "Get child subnets (slaves).")]
|
||||
public SwitchParameter Slaves { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 2,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "Get child subnets recursively.")]
|
||||
public SwitchParameter Recurse { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 1,
|
||||
ParameterSetName = "ByVlanNumber",
|
||||
HelpMessage = "The L2 domain ID to narrow VLAN search.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? VlanDomainId { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var controller = ApiController.Subnets;
|
||||
var identifiers = new List<string>();
|
||||
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
case "ByCIDR":
|
||||
identifiers.Add("cidr");
|
||||
identifiers.Add(CIDR!);
|
||||
break;
|
||||
|
||||
case "ByID":
|
||||
identifiers.Add(Id!.Value.ToString());
|
||||
if (Slaves.IsPresent)
|
||||
{
|
||||
identifiers.Add(Recurse.IsPresent ? "slaves_recursive" : "slaves");
|
||||
}
|
||||
break;
|
||||
|
||||
case "BySectionId":
|
||||
controller = ApiController.Sections;
|
||||
identifiers.Add(SectionId!.Value.ToString());
|
||||
identifiers.Add("subnets");
|
||||
break;
|
||||
|
||||
case "BySectionName":
|
||||
controller = ApiController.Sections;
|
||||
var section = GetSectionByName(SectionName!);
|
||||
identifiers.Add(section.Id.ToString());
|
||||
identifiers.Add("subnets");
|
||||
break;
|
||||
|
||||
case "ByVrfId":
|
||||
controller = ApiController.Vrf;
|
||||
identifiers.Add(VrfId!.Value.ToString());
|
||||
identifiers.Add("subnets");
|
||||
break;
|
||||
|
||||
case "ByVlanId":
|
||||
controller = ApiController.Vlan;
|
||||
identifiers.Add(VlanId!.Value.ToString());
|
||||
identifiers.Add("subnets");
|
||||
AddSectionIdentifier(identifiers);
|
||||
break;
|
||||
|
||||
case "ByVlanNumber":
|
||||
controller = ApiController.Vlan;
|
||||
var vlan = FindVlanByNumber(VlanNumber!.Value, VlanDomainId);
|
||||
identifiers.Add(vlan.Id.ToString());
|
||||
identifiers.Add("subnets");
|
||||
AddSectionIdentifier(identifiers);
|
||||
break;
|
||||
}
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", controller, ModelType.Subnetwork, null, null, identifiers.ToArray()
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetSubnetError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
|
||||
private Section GetSectionByName(string name)
|
||||
{
|
||||
var section = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Sections, ModelType.Section, null, null, new[] { name }
|
||||
).GetAwaiter().GetResult() as Section;
|
||||
|
||||
if (section == null)
|
||||
{
|
||||
throw new ItemNotFoundException($"Section '{name}' not found.");
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
private Vlan FindVlanByNumber(int number, int? domainId)
|
||||
{
|
||||
var vlans = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Vlan, ModelType.Vlan, null, null,
|
||||
new[] { "search", number.ToString() }
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
if (vlans == null)
|
||||
{
|
||||
throw new ItemNotFoundException($"VLAN {number} not found.");
|
||||
}
|
||||
|
||||
Vlan? foundVlan = null;
|
||||
|
||||
if (vlans is System.Collections.IEnumerable enumerable)
|
||||
{
|
||||
foreach (var v in enumerable)
|
||||
{
|
||||
if (v is Vlan vlan)
|
||||
{
|
||||
if (domainId.HasValue && vlan.DomainId != domainId.Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (foundVlan != null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Multiple VLANs with number {number} exist. Specify VlanDomainId to narrow the search.");
|
||||
}
|
||||
|
||||
foundVlan = vlan;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundVlan == null)
|
||||
{
|
||||
throw new ItemNotFoundException($"VLAN {number} not found.");
|
||||
}
|
||||
|
||||
return foundVlan;
|
||||
}
|
||||
|
||||
private void AddSectionIdentifier(List<string> identifiers)
|
||||
{
|
||||
if (SectionId.HasValue)
|
||||
{
|
||||
identifiers.Add(SectionId.Value.ToString());
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(SectionName))
|
||||
{
|
||||
var section = GetSectionByName(SectionName);
|
||||
identifiers.Add(section.Id.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
86
classlib/Cmdlets/GetSubnetUsageCmdlet.cs
Normal file
86
classlib/Cmdlets/GetSubnetUsageCmdlet.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves subnet usage statistics from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "SubnetUsage", DefaultParameterSetName = "ByID")]
|
||||
public class GetSubnetUsageCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByCIDR",
|
||||
HelpMessage = "The subnet in CIDR notation.")]
|
||||
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? CIDR { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The subnet ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetObject",
|
||||
HelpMessage = "The subnet object.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Subnetwork? SubnetObject { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var subnetId = GetSubnetId();
|
||||
var identifiers = new List<string> { subnetId.ToString(), "usage" };
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Subnets, null, null, null, identifiers.ToArray()
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetSubnetUsageError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
|
||||
private int GetSubnetId()
|
||||
{
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
case "ByCIDR":
|
||||
var subnet = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
|
||||
new[] { "cidr", CIDR! }
|
||||
).GetAwaiter().GetResult() as Subnetwork;
|
||||
|
||||
if (subnet == null)
|
||||
{
|
||||
throw new ItemNotFoundException($"Subnet '{CIDR}' not found.");
|
||||
}
|
||||
return subnet.Id;
|
||||
|
||||
case "BySubnetObject":
|
||||
return SubnetObject!.Id;
|
||||
|
||||
default:
|
||||
return Id!.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
94
classlib/Cmdlets/GetTagCmdlet.cs
Normal file
94
classlib/Cmdlets/GetTagCmdlet.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves tag information from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Tag", DefaultParameterSetName = "NoParams")]
|
||||
[OutputType(typeof(Tag))]
|
||||
public class GetTagCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The tag ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByAddressObject",
|
||||
HelpMessage = "Get the tag associated with this address.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Address? AddressObject { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetObject",
|
||||
HelpMessage = "Get the tag associated with this subnet.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Subnetwork? SubnetObject { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var identifiers = new List<string> { "tags" };
|
||||
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
case "ByID":
|
||||
if (Id.HasValue)
|
||||
{
|
||||
identifiers.Add(Id.Value.ToString());
|
||||
}
|
||||
break;
|
||||
|
||||
case "ByAddressObject":
|
||||
if (AddressObject?.TagId > 0)
|
||||
{
|
||||
identifiers.Add(AddressObject.TagId.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case "BySubnetObject":
|
||||
if (SubnetObject?.TagId > 0)
|
||||
{
|
||||
identifiers.Add(SubnetObject.TagId.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Addresses, ModelType.Tag, null, null, identifiers.ToArray()
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetTagError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
121
classlib/Cmdlets/GetVlanCmdlet.cs
Normal file
121
classlib/Cmdlets/GetVlanCmdlet.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves VLAN information from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Vlan", DefaultParameterSetName = "NoParams")]
|
||||
[OutputType(typeof(Vlan))]
|
||||
public class GetVlanCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The VLAN ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByNumber",
|
||||
HelpMessage = "The VLAN number.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Number { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByL2Domain",
|
||||
HelpMessage = "The L2 domain ID to get VLANs from.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? L2DomainId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetObject",
|
||||
HelpMessage = "Get the VLAN associated with this subnet.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Subnetwork? SubnetObject { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByDomainObject",
|
||||
HelpMessage = "Get VLANs in this L2 domain.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Domain? DomainObject { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var controller = ApiController.Vlan;
|
||||
var identifiers = new List<string>();
|
||||
|
||||
switch (ParameterSetName)
|
||||
{
|
||||
case "ByID":
|
||||
identifiers.Add(Id!.Value.ToString());
|
||||
break;
|
||||
|
||||
case "ByNumber":
|
||||
identifiers.Add("search");
|
||||
identifiers.Add(Number!.Value.ToString());
|
||||
break;
|
||||
|
||||
case "ByL2Domain":
|
||||
controller = ApiController.L2Domains;
|
||||
identifiers.Add(L2DomainId!.Value.ToString());
|
||||
identifiers.Add(ApiSubController.Vlans.ToString().ToLowerInvariant());
|
||||
break;
|
||||
|
||||
case "BySubnetObject":
|
||||
if (SubnetObject == null || SubnetObject.VlanId <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
identifiers.Add(SubnetObject.VlanId.ToString());
|
||||
break;
|
||||
|
||||
case "ByDomainObject":
|
||||
if (DomainObject != null)
|
||||
{
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.L2Domains, ModelType.Vlan, ApiSubController.Vlans,
|
||||
null, new[] { DomainObject.Id.ToString() }
|
||||
).GetAwaiter().GetResult();
|
||||
WriteResult(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var vlanResult = RequestHelper.InvokeRequest(
|
||||
"GET", controller, ModelType.Vlan, null, null,
|
||||
identifiers.Count > 0 ? identifiers.ToArray() : null
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(vlanResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetVlanError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
48
classlib/Cmdlets/GetVrfCmdlet.cs
Normal file
48
classlib/Cmdlets/GetVrfCmdlet.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves VRF information from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Get, "Vrf", DefaultParameterSetName = "NoParams")]
|
||||
[OutputType(typeof(Vrf))]
|
||||
public class GetVrfCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByID",
|
||||
HelpMessage = "The VRF ID.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var identifiers = new List<string>();
|
||||
|
||||
if (Id.HasValue)
|
||||
{
|
||||
identifiers.Add(Id.Value.ToString());
|
||||
}
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Vrf, ModelType.Vrf, null, null,
|
||||
identifiers.Count > 0 ? identifiers.ToArray() : null
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "GetVrfError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
142
classlib/Cmdlets/NewAddressCmdlet.cs
Normal file
142
classlib/Cmdlets/NewAddressCmdlet.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new IP address entry in phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.New, "Address", DefaultParameterSetName = "BySubnetId")]
|
||||
[OutputType(typeof(Address))]
|
||||
public class NewAddressCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetId",
|
||||
HelpMessage = "The subnet ID to create the address in.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? SubnetId { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "BySubnetObject",
|
||||
HelpMessage = "The subnet object to create the address in.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Subnetwork? SubnetObject { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 1,
|
||||
HelpMessage = "The IP address to create.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string IP { get; set; } = string.Empty;
|
||||
|
||||
[Parameter(Mandatory = false, Position = 2, HelpMessage = "Mark this address as a gateway.")]
|
||||
public SwitchParameter Gateway { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 3, HelpMessage = "Description for the address.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 4, HelpMessage = "Hostname for the address.")]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 5, HelpMessage = "MAC address.")]
|
||||
public string? MAC { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 6, HelpMessage = "Owner of the address.")]
|
||||
public string? Owner { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 7, HelpMessage = "Tag ID for the address.")]
|
||||
public int? TagId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 8, HelpMessage = "Ignore PTR record generation.")]
|
||||
public SwitchParameter PTRIgnore { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 9, HelpMessage = "PTR record ID.")]
|
||||
public int? PTRId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 10, HelpMessage = "Note for the address.")]
|
||||
public string? Note { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 11, HelpMessage = "Exclude from ping scanning.")]
|
||||
public SwitchParameter ExcludePing { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 12, HelpMessage = "Associated device ID.")]
|
||||
public int? DeviceId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 13, HelpMessage = "Port information.")]
|
||||
public string? Port { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 14, HelpMessage = "Custom fields as a hashtable or PSObject.")]
|
||||
public object? CustomFields { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var actualSubnetId = ParameterSetName == "BySubnetObject"
|
||||
? SubnetObject!.Id
|
||||
: SubnetId!.Value;
|
||||
|
||||
var body = BuildRequestBody(actualSubnetId);
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"POST", ApiController.Addresses, null, null, body
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
// Fetch the created address to return it
|
||||
var address = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Addresses, ModelType.Address, null, null,
|
||||
new[] { "search", IP }
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(address);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "NewAddressError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, object> BuildRequestBody(int subnetId)
|
||||
{
|
||||
var body = new Dictionary<string, object>
|
||||
{
|
||||
["subnetId"] = subnetId,
|
||||
["ip"] = IP
|
||||
};
|
||||
|
||||
if (Gateway.IsPresent) body["is_gateway"] = "1";
|
||||
if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
|
||||
if (!string.IsNullOrEmpty(Hostname)) body["hostname"] = Hostname;
|
||||
if (!string.IsNullOrEmpty(MAC)) body["mac"] = MAC;
|
||||
if (!string.IsNullOrEmpty(Owner)) body["owner"] = Owner;
|
||||
if (TagId.HasValue) body["tag"] = TagId.Value;
|
||||
if (PTRIgnore.IsPresent) body["PTRignore"] = "1";
|
||||
if (PTRId.HasValue) body["PTR"] = PTRId.Value;
|
||||
if (!string.IsNullOrEmpty(Note)) body["note"] = Note;
|
||||
if (ExcludePing.IsPresent) body["excludePing"] = "1";
|
||||
if (DeviceId.HasValue) body["deviceId"] = DeviceId.Value;
|
||||
if (!string.IsNullOrEmpty(Port)) body["port"] = Port;
|
||||
|
||||
foreach (var kvp in ConvertCustomFields(CustomFields))
|
||||
{
|
||||
body[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
118
classlib/Cmdlets/NewFirstFreeIPCmdlet.cs
Normal file
118
classlib/Cmdlets/NewFirstFreeIPCmdlet.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new address using the first available IP in a subnet.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.New, "FirstFreeIP")]
|
||||
[OutputType(typeof(Address))]
|
||||
public class NewFirstFreeIPCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
HelpMessage = "The subnet ID to create the address in.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string SubnetId { get; set; } = string.Empty;
|
||||
|
||||
[Parameter(Mandatory = false, Position = 1, HelpMessage = "Mark this address as a gateway.")]
|
||||
public SwitchParameter Gateway { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 2, HelpMessage = "Description for the address.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 3, HelpMessage = "Hostname for the address.")]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 4, HelpMessage = "MAC address.")]
|
||||
public string? MAC { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 5, HelpMessage = "Owner of the address.")]
|
||||
public string? Owner { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 6, HelpMessage = "Tag ID for the address.")]
|
||||
public string? TagId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 7, HelpMessage = "Ignore PTR record generation.")]
|
||||
public SwitchParameter PTRIgnore { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 8, HelpMessage = "PTR record ID.")]
|
||||
public string? PTRId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 9, HelpMessage = "Note for the address.")]
|
||||
public string? Note { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 10, HelpMessage = "Exclude from ping scanning.")]
|
||||
public SwitchParameter ExcludePing { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 11, HelpMessage = "Associated device ID.")]
|
||||
public string? DeviceId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 12, HelpMessage = "Port information.")]
|
||||
public string? Port { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Custom fields as a hashtable or PSObject.")]
|
||||
public object? CustomFields { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var identifiers = new[] { "first_free" };
|
||||
var body = BuildRequestBody();
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"POST", ApiController.Addresses, null, null, body, identifiers
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
var ip = result.ToString();
|
||||
var address = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Addresses, ModelType.Address, null, null,
|
||||
new[] { "search", ip! }
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(address);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "NewFirstFreeIPError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, object> BuildRequestBody()
|
||||
{
|
||||
var body = new Dictionary<string, object>
|
||||
{
|
||||
["subnetId"] = SubnetId
|
||||
};
|
||||
|
||||
if (Gateway.IsPresent) body["is_gateway"] = "1";
|
||||
if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
|
||||
if (!string.IsNullOrEmpty(Hostname)) body["hostname"] = Hostname;
|
||||
if (!string.IsNullOrEmpty(MAC)) body["mac"] = MAC;
|
||||
if (!string.IsNullOrEmpty(Owner)) body["owner"] = Owner;
|
||||
if (!string.IsNullOrEmpty(TagId)) body["tag"] = TagId;
|
||||
if (PTRIgnore.IsPresent) body["PTRignore"] = "1";
|
||||
if (!string.IsNullOrEmpty(PTRId)) body["PTR"] = PTRId;
|
||||
if (!string.IsNullOrEmpty(Note)) body["note"] = Note;
|
||||
if (ExcludePing.IsPresent) body["excludePing"] = "1";
|
||||
if (!string.IsNullOrEmpty(DeviceId)) body["deviceId"] = DeviceId;
|
||||
if (!string.IsNullOrEmpty(Port)) body["port"] = Port;
|
||||
|
||||
foreach (var kvp in ConvertCustomFields(CustomFields))
|
||||
{
|
||||
body[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
92
classlib/Cmdlets/NewSessionCmdlet.cs
Normal file
92
classlib/Cmdlets/NewSessionCmdlet.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new phpIPAM API session.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.New, "Session", DefaultParameterSetName = "Credentials")]
|
||||
[OutputType(typeof(Session))]
|
||||
public class NewSessionCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
HelpMessage = "The phpIPAM server URL (must start with http:// or https://).")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
[ValidatePattern("^https?://")]
|
||||
public string URL { get; set; } = string.Empty;
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 1,
|
||||
HelpMessage = "The API application ID configured in phpIPAM.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string AppID { get; set; } = string.Empty;
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 2,
|
||||
ParameterSetName = "Credentials",
|
||||
HelpMessage = "The credentials (username and password) for authentication.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public PSCredential? Credentials { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 2,
|
||||
ParameterSetName = "Token",
|
||||
HelpMessage = "The static API token for authentication.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string? Token { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = false,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 3,
|
||||
HelpMessage = "If specified, SSL certificate errors will be ignored.")]
|
||||
public SwitchParameter IgnoreSSL { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
Session session;
|
||||
|
||||
if (ParameterSetName == "Credentials" && Credentials != null)
|
||||
{
|
||||
session = SessionManager.CreateSessionWithCredentialsAsync(
|
||||
URL,
|
||||
AppID,
|
||||
Credentials,
|
||||
IgnoreSSL.IsPresent
|
||||
).GetAwaiter().GetResult();
|
||||
}
|
||||
else if (ParameterSetName == "Token" && Token != null)
|
||||
{
|
||||
session = SessionManager.CreateSessionWithToken(URL, AppID, Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Invalid parameter set. Provide either Credentials or Token.");
|
||||
}
|
||||
|
||||
WriteObject(session);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "NewSessionError", ErrorCategory.AuthenticationError, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
143
classlib/Cmdlets/NewSubnetCmdlet.cs
Normal file
143
classlib/Cmdlets/NewSubnetCmdlet.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new subnet in phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.New, "Subnet")]
|
||||
[OutputType(typeof(Subnetwork))]
|
||||
public class NewSubnetCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
HelpMessage = "The subnet in CIDR notation (e.g., 192.168.1.0/24).")]
|
||||
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string CIDR { get; set; } = string.Empty;
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 1,
|
||||
HelpMessage = "The section ID to create the subnet in.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int SectionId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 2, HelpMessage = "Description for the subnet.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 3, HelpMessage = "VLAN ID to associate.")]
|
||||
public int? VlanId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 4, HelpMessage = "VRF ID to associate.")]
|
||||
public int? VrfId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 5, HelpMessage = "Master subnet ID for hierarchy.")]
|
||||
public int? MasterSubnetId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 6, HelpMessage = "Nameserver ID.")]
|
||||
public int? NameserverId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 7, HelpMessage = "Show subnet name.")]
|
||||
public SwitchParameter ShowName { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 8, HelpMessage = "Enable recursive DNS.")]
|
||||
public SwitchParameter DNSRecursive { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 9, HelpMessage = "Enable DNS records.")]
|
||||
public SwitchParameter DNSRecords { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 10, HelpMessage = "Allow IP requests.")]
|
||||
public SwitchParameter AllowRequests { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 11, HelpMessage = "Scan agent ID.")]
|
||||
public int? ScanAgentId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 12, HelpMessage = "Enable subnet discovery.")]
|
||||
public SwitchParameter DiscoverSubnet { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 13, HelpMessage = "Mark subnet as full.")]
|
||||
public SwitchParameter IsFull { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 14, HelpMessage = "Tag ID for the subnet.")]
|
||||
public int? TagId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 15, HelpMessage = "Usage threshold percentage (1-100).")]
|
||||
[ValidateRange(1, 100)]
|
||||
public int? Threshold { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, Position = 16, HelpMessage = "Location ID.")]
|
||||
public int? LocationId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Custom fields as a hashtable or PSObject.")]
|
||||
public object? CustomFields { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var body = BuildRequestBody();
|
||||
|
||||
var result = RequestHelper.InvokeRequest(
|
||||
"POST", ApiController.Subnets, null, null, body
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
// Get the created subnet
|
||||
var subnet = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
|
||||
new[] { "cidr", CIDR }
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(subnet);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "NewSubnetError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, object> BuildRequestBody()
|
||||
{
|
||||
var parts = CIDR.Split('/');
|
||||
var body = new Dictionary<string, object>
|
||||
{
|
||||
["subnet"] = parts[0],
|
||||
["mask"] = parts[1],
|
||||
["sectionId"] = SectionId
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
|
||||
if (VlanId.HasValue) body["vlanId"] = VlanId.Value;
|
||||
if (VrfId.HasValue) body["vrfId"] = VrfId.Value;
|
||||
if (MasterSubnetId.HasValue) body["masterSubnetId"] = MasterSubnetId.Value;
|
||||
if (NameserverId.HasValue) body["nameserverId"] = NameserverId.Value;
|
||||
if (ShowName.IsPresent) body["showName"] = "1";
|
||||
if (DNSRecursive.IsPresent) body["DNSrecursive"] = "1";
|
||||
if (DNSRecords.IsPresent) body["DNSrecords"] = "1";
|
||||
if (AllowRequests.IsPresent) body["allowRequests"] = "1";
|
||||
if (ScanAgentId.HasValue) body["scanAgent"] = ScanAgentId.Value;
|
||||
if (DiscoverSubnet.IsPresent) body["discoverSubnet"] = "1";
|
||||
if (IsFull.IsPresent) body["isFull"] = "1";
|
||||
if (TagId.HasValue) body["state"] = TagId.Value;
|
||||
if (Threshold.HasValue) body["threshold"] = Threshold.Value;
|
||||
if (LocationId.HasValue) body["location"] = LocationId.Value;
|
||||
|
||||
foreach (var kvp in ConvertCustomFields(CustomFields))
|
||||
{
|
||||
body[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
53
classlib/Cmdlets/RemoveAddressCmdlet.cs
Normal file
53
classlib/Cmdlets/RemoveAddressCmdlet.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Removes an IP address entry from phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Remove, "Address", DefaultParameterSetName = "ById", SupportsShouldProcess = true)]
|
||||
public class RemoveAddressCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ById",
|
||||
HelpMessage = "The address ID to remove.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByAddressObject",
|
||||
HelpMessage = "The address object to remove.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Address? AddressObject { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var addressId = ParameterSetName == "ById" ? Id : AddressObject!.Id;
|
||||
var identifiers = new[] { addressId.ToString() };
|
||||
|
||||
if (ShouldProcess($"Address ID: {addressId}", "Remove"))
|
||||
{
|
||||
RequestHelper.InvokeRequest(
|
||||
"DELETE", ApiController.Addresses, null, null, null, identifiers
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteVerbose($"Address {addressId} removed successfully.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "RemoveAddressError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
128
classlib/Cmdlets/SetAddressCmdlet.cs
Normal file
128
classlib/Cmdlets/SetAddressCmdlet.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing IP address entry in phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Set, "Address", DefaultParameterSetName = "ById")]
|
||||
[OutputType(typeof(Address))]
|
||||
public class SetAddressCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ById",
|
||||
HelpMessage = "The address ID to update.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int? Id { get; set; }
|
||||
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
ParameterSetName = "ByAddressObject",
|
||||
HelpMessage = "The address object to update.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public Address? AddressObject { get; set; }
|
||||
|
||||
[Parameter(Position = 1, HelpMessage = "Set as gateway address.")]
|
||||
public bool? Gateway { get; set; }
|
||||
|
||||
[Parameter(Position = 2, HelpMessage = "Description for the address.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Parameter(Position = 3, HelpMessage = "Hostname for the address.")]
|
||||
public string? Hostname { get; set; }
|
||||
|
||||
[Parameter(Position = 4, HelpMessage = "MAC address.")]
|
||||
public string? MAC { get; set; }
|
||||
|
||||
[Parameter(Position = 5, HelpMessage = "Owner of the address.")]
|
||||
public string? Owner { get; set; }
|
||||
|
||||
[Parameter(Position = 6, HelpMessage = "Tag ID for the address.")]
|
||||
public int? TagId { get; set; }
|
||||
|
||||
[Parameter(Position = 7, HelpMessage = "Ignore PTR record generation.")]
|
||||
public bool? PTRIgnore { get; set; }
|
||||
|
||||
[Parameter(Position = 8, HelpMessage = "PTR record ID.")]
|
||||
public int? PTRId { get; set; }
|
||||
|
||||
[Parameter(Position = 9, HelpMessage = "Note for the address.")]
|
||||
public string? Note { get; set; }
|
||||
|
||||
[Parameter(Position = 10, HelpMessage = "Exclude from ping scanning.")]
|
||||
public bool? ExcludePing { get; set; }
|
||||
|
||||
[Parameter(Position = 11, HelpMessage = "Associated device ID.")]
|
||||
public int? DeviceId { get; set; }
|
||||
|
||||
[Parameter(Position = 12, HelpMessage = "Port information.")]
|
||||
public string? Port { get; set; }
|
||||
|
||||
[Parameter(HelpMessage = "Custom fields as a hashtable or PSObject.")]
|
||||
public object? CustomFields { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var addressId = ParameterSetName == "ById" ? Id!.Value : AddressObject!.Id;
|
||||
var identifiers = new[] { addressId.ToString() };
|
||||
var body = BuildRequestBody();
|
||||
|
||||
try
|
||||
{
|
||||
RequestHelper.InvokeRequest(
|
||||
"PATCH", ApiController.Addresses, null, null, body, identifiers
|
||||
).GetAwaiter().GetResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Always return the updated address
|
||||
var address = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Addresses, ModelType.Address, null, null, identifiers
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(address);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "SetAddressError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, object> BuildRequestBody()
|
||||
{
|
||||
var body = new Dictionary<string, object>();
|
||||
|
||||
if (Gateway.HasValue) body["is_gateway"] = Gateway.Value;
|
||||
if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
|
||||
if (!string.IsNullOrEmpty(Hostname)) body["hostname"] = Hostname;
|
||||
if (!string.IsNullOrEmpty(MAC)) body["mac"] = MAC;
|
||||
if (!string.IsNullOrEmpty(Owner)) body["owner"] = Owner;
|
||||
if (TagId.HasValue) body["tag"] = TagId.Value;
|
||||
if (PTRIgnore.HasValue) body["PTRignore"] = PTRIgnore.Value;
|
||||
if (PTRId.HasValue) body["PTR"] = PTRId.Value;
|
||||
if (!string.IsNullOrEmpty(Note)) body["note"] = Note;
|
||||
if (ExcludePing.HasValue) body["excludePing"] = ExcludePing.Value;
|
||||
if (DeviceId.HasValue) body["deviceId"] = DeviceId.Value;
|
||||
if (!string.IsNullOrEmpty(Port)) body["port"] = Port;
|
||||
|
||||
foreach (var kvp in ConvertCustomFields(CustomFields))
|
||||
{
|
||||
body[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
123
classlib/Cmdlets/SetSubnetCmdlet.cs
Normal file
123
classlib/Cmdlets/SetSubnetCmdlet.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
namespace PS.IPAM.Cmdlets;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using PS.IPAM.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing subnet in phpIPAM.
|
||||
/// </summary>
|
||||
[Cmdlet(VerbsCommon.Set, "Subnet")]
|
||||
[OutputType(typeof(Subnetwork))]
|
||||
public class SetSubnetCmdlet : BaseCmdlet
|
||||
{
|
||||
[Parameter(
|
||||
Mandatory = true,
|
||||
ValueFromPipeline = true,
|
||||
ValueFromPipelineByPropertyName = true,
|
||||
Position = 0,
|
||||
HelpMessage = "The subnet ID to update.")]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Description for the subnet.")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "VLAN ID to associate.")]
|
||||
public int? VlanId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "VRF ID to associate.")]
|
||||
public int? VrfId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Master subnet ID for hierarchy.")]
|
||||
public int? MasterSubnetId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Nameserver ID.")]
|
||||
public int? NameserverId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Show subnet name.")]
|
||||
public SwitchParameter ShowName { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Enable recursive DNS.")]
|
||||
public SwitchParameter DNSRecursive { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Enable DNS records.")]
|
||||
public SwitchParameter DNSRecords { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Allow IP requests.")]
|
||||
public SwitchParameter AllowRequests { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Scan agent ID.")]
|
||||
public int? ScanAgentId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Enable subnet discovery.")]
|
||||
public SwitchParameter DiscoverSubnet { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Mark subnet as full.")]
|
||||
public SwitchParameter IsFull { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Tag ID for the subnet.")]
|
||||
public int? TagId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Usage threshold percentage (1-100).")]
|
||||
[ValidateRange(1, 100)]
|
||||
public int? Threshold { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Location ID.")]
|
||||
public int? LocationId { get; set; }
|
||||
|
||||
[Parameter(Mandatory = false, HelpMessage = "Custom fields as a hashtable or PSObject.")]
|
||||
public object? CustomFields { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
var identifiers = new[] { Id.ToString() };
|
||||
var body = BuildRequestBody();
|
||||
|
||||
RequestHelper.InvokeRequest(
|
||||
"PATCH", ApiController.Subnets, null, null, body, identifiers
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
var subnet = RequestHelper.InvokeRequest(
|
||||
"GET", ApiController.Subnets, ModelType.Subnetwork, null, null, identifiers
|
||||
).GetAwaiter().GetResult();
|
||||
|
||||
WriteResult(subnet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteError(new ErrorRecord(ex, "SetSubnetError", ErrorCategory.InvalidOperation, null));
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, object> BuildRequestBody()
|
||||
{
|
||||
var body = new Dictionary<string, object>();
|
||||
|
||||
if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
|
||||
if (VlanId.HasValue) body["vlanId"] = VlanId.Value;
|
||||
if (VrfId.HasValue) body["vrfId"] = VrfId.Value;
|
||||
if (MasterSubnetId.HasValue) body["masterSubnetId"] = MasterSubnetId.Value;
|
||||
if (NameserverId.HasValue) body["nameserverId"] = NameserverId.Value;
|
||||
if (ShowName.IsPresent) body["showName"] = "1";
|
||||
if (DNSRecursive.IsPresent) body["DNSrecursive"] = "1";
|
||||
if (DNSRecords.IsPresent) body["DNSrecords"] = "1";
|
||||
if (AllowRequests.IsPresent) body["allowRequests"] = "1";
|
||||
if (ScanAgentId.HasValue) body["scanAgent"] = ScanAgentId.Value;
|
||||
if (DiscoverSubnet.IsPresent) body["discoverSubnet"] = "1";
|
||||
if (IsFull.IsPresent) body["isFull"] = "1";
|
||||
if (TagId.HasValue) body["state"] = TagId.Value;
|
||||
if (Threshold.HasValue) body["threshold"] = Threshold.Value;
|
||||
if (LocationId.HasValue) body["location"] = LocationId.Value;
|
||||
|
||||
foreach (var kvp in ConvertCustomFields(CustomFields))
|
||||
{
|
||||
body[kvp.Key] = kvp.Value;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
||||
441
classlib/Helpers/RequestHelper.cs
Normal file
441
classlib/Helpers/RequestHelper.cs
Normal file
@@ -0,0 +1,441 @@
|
||||
namespace PS.IPAM.Helpers;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for making HTTP requests to the phpIPAM API.
|
||||
/// </summary>
|
||||
public static class RequestHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Handler for testing - allows injecting a mock HTTP handler.
|
||||
/// </summary>
|
||||
public static HttpMessageHandler? TestHttpHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Invokes an HTTP request to the phpIPAM API.
|
||||
/// </summary>
|
||||
/// <param name="method">The HTTP method (GET, POST, PATCH, DELETE).</param>
|
||||
/// <param name="controller">The API controller to call.</param>
|
||||
/// <param name="modelType">The expected model type for response conversion.</param>
|
||||
/// <param name="subController">Optional sub-controller for nested endpoints.</param>
|
||||
/// <param name="parameters">Optional request body parameters.</param>
|
||||
/// <param name="identifiers">Optional path identifiers.</param>
|
||||
/// <param name="ignoreSsl">Whether to ignore SSL certificate errors.</param>
|
||||
/// <returns>The deserialized response data, or null if not found.</returns>
|
||||
public static async Task<object?> InvokeRequestAsync(
|
||||
HttpMethod method,
|
||||
ApiController controller,
|
||||
ModelType? modelType = null,
|
||||
ApiSubController? subController = null,
|
||||
object? parameters = null,
|
||||
string[]? identifiers = null,
|
||||
bool ignoreSsl = false)
|
||||
{
|
||||
EnsureValidSession();
|
||||
|
||||
var session = SessionManager.CurrentSession!;
|
||||
var uri = BuildUri(session, controller, subController, identifiers);
|
||||
|
||||
using var client = SessionManager.CreateHttpClient(ignoreSsl, TestHttpHandler);
|
||||
ConfigureClient(client, session);
|
||||
|
||||
var response = await SendRequestAsync(client, method, uri, parameters);
|
||||
|
||||
if (response == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
throw new HttpRequestException($"Request failed with status {response.StatusCode}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(responseContent))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ParseResponse(responseContent, modelType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overload for backward compatibility using string method names.
|
||||
/// </summary>
|
||||
public static Task<object?> InvokeRequest(
|
||||
string method,
|
||||
ApiController controller,
|
||||
ModelType? modelType = null,
|
||||
ApiSubController? subController = null,
|
||||
object? parameters = null,
|
||||
string[]? identifiers = null,
|
||||
bool ignoreSsl = false)
|
||||
{
|
||||
var httpMethod = method.ToUpperInvariant() switch
|
||||
{
|
||||
"GET" => HttpMethod.Get,
|
||||
"POST" => HttpMethod.Post,
|
||||
"PATCH" => new HttpMethod("PATCH"),
|
||||
"DELETE" => HttpMethod.Delete,
|
||||
"PUT" => HttpMethod.Put,
|
||||
_ => throw new ArgumentException($"Unsupported HTTP method: {method}", nameof(method))
|
||||
};
|
||||
|
||||
return InvokeRequestAsync(httpMethod, controller, modelType, subController, parameters, identifiers, ignoreSsl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes an expired session.
|
||||
/// </summary>
|
||||
public static async Task RefreshSessionAsync()
|
||||
{
|
||||
var session = SessionManager.CurrentSession;
|
||||
if (session == null)
|
||||
{
|
||||
throw new InvalidOperationException("No session available!");
|
||||
}
|
||||
|
||||
var status = SessionManager.GetSessionStatus();
|
||||
if (status == SessionStatus.Valid)
|
||||
{
|
||||
// Just refresh the token
|
||||
await InvokeRequestAsync(new HttpMethod("PATCH"), ApiController.User);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == SessionStatus.Expired && session.Credentials is PSCredential creds)
|
||||
{
|
||||
await SessionManager.CreateSessionWithCredentialsAsync(
|
||||
session.URL,
|
||||
session.AppID,
|
||||
creds,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureValidSession()
|
||||
{
|
||||
var status = SessionManager.GetSessionStatus();
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case SessionStatus.NoSession:
|
||||
throw new InvalidOperationException("No session available!");
|
||||
|
||||
case SessionStatus.Expired:
|
||||
RefreshSessionAsync().GetAwaiter().GetResult();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildUri(
|
||||
Session session,
|
||||
ApiController controller,
|
||||
ApiSubController? subController,
|
||||
string[]? identifiers)
|
||||
{
|
||||
var controllerName = GetControllerName(controller);
|
||||
var uri = $"{session.URL}/api/{session.AppID}/{controllerName}";
|
||||
|
||||
if (subController.HasValue)
|
||||
{
|
||||
uri += $"/{GetSubControllerName(subController.Value)}";
|
||||
}
|
||||
|
||||
if (identifiers is { Length: > 0 })
|
||||
{
|
||||
uri += $"/{string.Join("/", identifiers)}/";
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
private static string GetControllerName(ApiController controller) => controller switch
|
||||
{
|
||||
ApiController.User => "user",
|
||||
ApiController.Vlan => "vlan",
|
||||
ApiController.Subnets => "subnets",
|
||||
ApiController.Addresses => "addresses",
|
||||
ApiController.Sections => "sections",
|
||||
ApiController.Vrf => "vrf",
|
||||
ApiController.L2Domains => "l2domains",
|
||||
ApiController.Tools => "tools",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(controller))
|
||||
};
|
||||
|
||||
private static string GetSubControllerName(ApiSubController subController) => subController switch
|
||||
{
|
||||
ApiSubController.Nameservers => "nameservers",
|
||||
ApiSubController.Tags => "tags",
|
||||
ApiSubController.Devices => "devices",
|
||||
ApiSubController.DeviceTypes => "device_types",
|
||||
ApiSubController.Vlans => "vlans",
|
||||
ApiSubController.Vrfs => "vrfs",
|
||||
ApiSubController.ScanAgents => "scanagents",
|
||||
ApiSubController.Locations => "locations",
|
||||
ApiSubController.Nat => "nat",
|
||||
ApiSubController.Racks => "racks",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(subController))
|
||||
};
|
||||
|
||||
private static void ConfigureClient(HttpClient client, Session session)
|
||||
{
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
switch (session.AuthType)
|
||||
{
|
||||
case AuthType.Credentials:
|
||||
client.DefaultRequestHeaders.Add("token", session.Token);
|
||||
break;
|
||||
case AuthType.Token:
|
||||
client.DefaultRequestHeaders.Add("phpipam-token", session.Token);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<HttpResponseMessage?> SendRequestAsync(
|
||||
HttpClient client,
|
||||
HttpMethod method,
|
||||
string uri,
|
||||
object? parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (method == HttpMethod.Get)
|
||||
{
|
||||
return await client.GetAsync(uri);
|
||||
}
|
||||
|
||||
if (method == HttpMethod.Delete)
|
||||
{
|
||||
return await client.DeleteAsync(uri);
|
||||
}
|
||||
|
||||
var jsonContent = parameters != null ? JsonConvert.SerializeObject(parameters) : "{}";
|
||||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||
|
||||
if (method == HttpMethod.Post)
|
||||
{
|
||||
return await client.PostAsync(uri, content);
|
||||
}
|
||||
|
||||
// PATCH, PUT, etc.
|
||||
var request = new HttpRequestMessage(method, uri) { Content = content };
|
||||
return await client.SendAsync(request);
|
||||
}
|
||||
catch (HttpRequestException ex) when (ex.Message.Contains("404"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static object? ParseResponse(string responseContent, ModelType? modelType)
|
||||
{
|
||||
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(responseContent);
|
||||
if (jsonResponse == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!modelType.HasValue)
|
||||
{
|
||||
return jsonResponse.data;
|
||||
}
|
||||
|
||||
return ConvertToTypedObjects(jsonResponse, modelType.Value);
|
||||
}
|
||||
|
||||
private static object? ConvertToTypedObjects(dynamic jsonResponse, ModelType modelType)
|
||||
{
|
||||
if (jsonResponse?.data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var data = jsonResponse.data;
|
||||
if (data is JArray array)
|
||||
{
|
||||
return array.Select(item => ConvertSingleObject(item, modelType)).ToList();
|
||||
}
|
||||
|
||||
return ConvertSingleObject(data, modelType);
|
||||
}
|
||||
|
||||
private static object? ConvertSingleObject(dynamic item, ModelType modelType)
|
||||
{
|
||||
if (item is not JObject jobject)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var customFields = ExtractCustomFields(jobject);
|
||||
|
||||
return modelType switch
|
||||
{
|
||||
ModelType.Address => CreateAddress(jobject, customFields),
|
||||
ModelType.Vlan => CreateVlan(jobject, customFields),
|
||||
ModelType.Subnetwork => CreateSubnetwork(jobject, customFields),
|
||||
ModelType.Vrf => CreateVrf(jobject, customFields),
|
||||
ModelType.Section => CreateSection(jobject),
|
||||
ModelType.Tag => CreateTag(jobject),
|
||||
ModelType.Nameserver => CreateNameserver(jobject),
|
||||
ModelType.Domain => CreateDomain(jobject),
|
||||
_ => jobject.ToObject<object>()
|
||||
};
|
||||
}
|
||||
|
||||
private static Dictionary<string, object>? ExtractCustomFields(JObject jobject)
|
||||
{
|
||||
var customFields = new Dictionary<string, object>();
|
||||
foreach (var prop in jobject.Properties().Where(p => p.Name.StartsWith("custom_")))
|
||||
{
|
||||
customFields[prop.Name] = prop.Value?.ToObject<object>() ?? string.Empty;
|
||||
}
|
||||
return customFields.Count > 0 ? customFields : null;
|
||||
}
|
||||
|
||||
#region Model Factory Methods
|
||||
|
||||
private static Address CreateAddress(JObject obj, Dictionary<string, object>? customFields) => new(
|
||||
obj["id"]?.ToObject<int>() ?? 0,
|
||||
obj["subnetId"]?.ToObject<int>() ?? 0,
|
||||
obj["ip"]?.ToString() ?? "",
|
||||
obj["is_gateway"]?.ToObject<bool>() ?? false,
|
||||
obj["description"]?.ToString() ?? "",
|
||||
obj["hostname"]?.ToString() ?? "",
|
||||
obj["mac"]?.ToString() ?? "",
|
||||
obj["owner"]?.ToString() ?? "",
|
||||
obj["tag"]?.ToObject<int>() ?? 0,
|
||||
obj["deviceId"]?.ToObject<int>() ?? 0,
|
||||
obj["location"]?.ToString() ?? "",
|
||||
obj["port"]?.ToString() ?? "",
|
||||
obj["note"]?.ToString() ?? "",
|
||||
obj["lastSeen"]?.ToObject<DateTime?>(),
|
||||
obj["excludePing"]?.ToObject<bool>() ?? false,
|
||||
obj["PTRignore"]?.ToObject<bool>() ?? false,
|
||||
obj["PTR"]?.ToObject<int>() ?? 0,
|
||||
obj["firewallAddressObject"]?.ToString() ?? "",
|
||||
obj["editDate"]?.ToObject<DateTime?>(),
|
||||
obj["customer_id"]?.ToObject<int>() ?? 0,
|
||||
customFields
|
||||
);
|
||||
|
||||
private static Vlan CreateVlan(JObject obj, Dictionary<string, object>? customFields) => new(
|
||||
obj["vlanId"]?.ToObject<int>() ?? 0,
|
||||
obj["domainId"]?.ToObject<int>() ?? 0,
|
||||
obj["name"]?.ToString() ?? "",
|
||||
obj["number"]?.ToObject<int>() ?? 0,
|
||||
obj["description"]?.ToString() ?? "",
|
||||
obj["editDate"]?.ToObject<DateTime?>(),
|
||||
obj["customer_id"]?.ToObject<int>() ?? 0,
|
||||
customFields
|
||||
);
|
||||
|
||||
private static Subnetwork CreateSubnetwork(JObject obj, Dictionary<string, object>? customFields) => new(
|
||||
obj["id"]?.ToObject<int>() ?? 0,
|
||||
obj["subnet"]?.ToString() ?? "",
|
||||
obj["mask"]?.ToObject<int>() ?? 0,
|
||||
obj["sectionId"]?.ToObject<int>() ?? 0,
|
||||
obj["description"]?.ToString() ?? "",
|
||||
obj["linked_subnet"]?.ToString() ?? "",
|
||||
obj["firewallAddressObject"]?.ToString() ?? "",
|
||||
obj["vrfId"]?.ToObject<int>() ?? 0,
|
||||
obj["masterSubnetId"]?.ToObject<int>() ?? 0,
|
||||
obj["allowRequests"]?.ToObject<bool>() ?? false,
|
||||
obj["vlanId"]?.ToObject<int>() ?? 0,
|
||||
obj["showName"]?.ToObject<bool>() ?? false,
|
||||
obj["deviceId"]?.ToObject<int>() ?? 0,
|
||||
obj["permissions"]?.ToString() ?? "",
|
||||
obj["pingSubnet"]?.ToObject<bool>() ?? false,
|
||||
obj["discoverSubnet"]?.ToObject<bool>() ?? false,
|
||||
obj["resolveDNS"]?.ToObject<bool>() ?? false,
|
||||
obj["DNSrecursive"]?.ToObject<bool>() ?? false,
|
||||
obj["DNSrecords"]?.ToObject<bool>() ?? false,
|
||||
obj["nameserverId"]?.ToObject<int>() ?? 0,
|
||||
obj["scanAgent"]?.ToObject<bool>() ?? false,
|
||||
obj["isFolder"]?.ToObject<bool>() ?? false,
|
||||
obj["isFull"]?.ToObject<bool>() ?? false,
|
||||
obj["isPool"]?.ToObject<bool>() ?? false,
|
||||
obj["state"]?.ToObject<int>() ?? 0,
|
||||
obj["threshold"]?.ToObject<int>() ?? 0,
|
||||
obj["location"]?.ToObject<int>() ?? 0,
|
||||
obj["editDate"]?.ToObject<DateTime?>(),
|
||||
obj["lastScan"]?.ToObject<DateTime?>(),
|
||||
obj["lastDiscovery"]?.ToObject<DateTime?>(),
|
||||
obj["calculation"]?.ToObject<object>() ?? new object(),
|
||||
customFields
|
||||
);
|
||||
|
||||
private static Vrf CreateVrf(JObject obj, Dictionary<string, object>? customFields) => new(
|
||||
obj["id"]?.ToObject<int>() ?? 0,
|
||||
obj["name"]?.ToString() ?? "",
|
||||
obj["rd"]?.ToString() ?? "",
|
||||
obj["description"]?.ToString() ?? "",
|
||||
obj["sections"]?.ToString() ?? "",
|
||||
obj["editDate"]?.ToObject<DateTime?>(),
|
||||
customFields
|
||||
);
|
||||
|
||||
private static Section CreateSection(JObject obj) => new(
|
||||
obj["id"]?.ToObject<int>() ?? 0,
|
||||
obj["name"]?.ToString() ?? "",
|
||||
obj["description"]?.ToString() ?? "",
|
||||
obj["masterSection"]?.ToObject<int>() ?? 0,
|
||||
obj["permissions"]?.ToString() ?? "",
|
||||
obj["strictMode"]?.ToObject<bool>() ?? false,
|
||||
obj["subnetOrdering"]?.ToString() ?? "",
|
||||
obj["order"]?.ToObject<int>() ?? 0,
|
||||
obj["editDate"]?.ToObject<DateTime?>(),
|
||||
obj["showSubnet"]?.ToObject<bool>() ?? false,
|
||||
obj["showVlan"]?.ToObject<bool>() ?? false,
|
||||
obj["showVRF"]?.ToObject<bool>() ?? false,
|
||||
obj["showSupernetOnly"]?.ToObject<bool>() ?? false,
|
||||
obj["DNS"]?.ToObject<int>() ?? 0
|
||||
);
|
||||
|
||||
private static Tag CreateTag(JObject obj) => new(
|
||||
obj["id"]?.ToObject<int>() ?? 0,
|
||||
obj["type"]?.ToString() ?? "",
|
||||
obj["showtag"]?.ToObject<bool>() ?? false,
|
||||
obj["bgcolor"]?.ToString() ?? "",
|
||||
obj["fgcolor"]?.ToString() ?? "",
|
||||
obj["compress"]?.ToString() ?? "",
|
||||
obj["locked"]?.ToString() ?? "",
|
||||
obj["updateTag"]?.ToObject<bool>() ?? false
|
||||
);
|
||||
|
||||
private static Nameserver CreateNameserver(JObject obj) => new(
|
||||
obj["id"]?.ToObject<int>() ?? 0,
|
||||
obj["name"]?.ToString() ?? "",
|
||||
obj["nameservers"]?.ToString() ?? "",
|
||||
obj["description"]?.ToString() ?? "",
|
||||
obj["permissions"]?.ToString() ?? "",
|
||||
obj["editDate"]?.ToObject<DateTime?>()
|
||||
);
|
||||
|
||||
private static Domain CreateDomain(JObject obj) => new(
|
||||
obj["id"]?.ToObject<int>() ?? 0,
|
||||
obj["name"]?.ToString() ?? "",
|
||||
obj["description"]?.ToString() ?? "",
|
||||
obj["sections"]?.ToString() ?? ""
|
||||
);
|
||||
|
||||
#endregion
|
||||
}
|
||||
165
classlib/Helpers/SessionManager.cs
Normal file
165
classlib/Helpers/SessionManager.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
namespace PS.IPAM.Helpers;
|
||||
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Manages phpIPAM API sessions including creation, validation, and lifecycle.
|
||||
/// </summary>
|
||||
public static class SessionManager
|
||||
{
|
||||
private static Session? _currentSession;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current active session.
|
||||
/// </summary>
|
||||
public static Session? CurrentSession
|
||||
{
|
||||
get => _currentSession;
|
||||
set => _currentSession = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the current session status.
|
||||
/// </summary>
|
||||
/// <returns>The session status indicating validity or issues.</returns>
|
||||
public static SessionStatus GetSessionStatus()
|
||||
{
|
||||
if (_currentSession == null)
|
||||
{
|
||||
return SessionStatus.NoSession;
|
||||
}
|
||||
|
||||
if (_currentSession.Expires == null)
|
||||
{
|
||||
return SessionStatus.Valid;
|
||||
}
|
||||
|
||||
return _currentSession.Expires < DateTime.Now
|
||||
? SessionStatus.Expired
|
||||
: SessionStatus.Valid;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new session using username/password credentials.
|
||||
/// </summary>
|
||||
/// <param name="url">The phpIPAM server URL.</param>
|
||||
/// <param name="appId">The API application ID.</param>
|
||||
/// <param name="credentials">The PowerShell credential object.</param>
|
||||
/// <param name="ignoreSsl">Whether to ignore SSL certificate errors.</param>
|
||||
/// <returns>The created session.</returns>
|
||||
public static async Task<Session> CreateSessionWithCredentialsAsync(
|
||||
string url,
|
||||
string appId,
|
||||
PSCredential credentials,
|
||||
bool ignoreSsl = false)
|
||||
{
|
||||
var uri = $"{url}/api/{appId}/user";
|
||||
var auth = Convert.ToBase64String(
|
||||
Encoding.UTF8.GetBytes($"{credentials.UserName}:{GetPasswordString(credentials)}"));
|
||||
|
||||
using var client = CreateHttpClient(ignoreSsl);
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
|
||||
|
||||
var response = await client.PostAsync(uri, null);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(content);
|
||||
|
||||
if (jsonResponse?.success != true)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
jsonResponse?.error?.ToString() ?? "Failed to create session");
|
||||
}
|
||||
|
||||
var token = jsonResponse.data.token.ToString();
|
||||
var expires = DateTime.Parse(jsonResponse.data.expires.ToString());
|
||||
|
||||
_currentSession = new Session(
|
||||
AuthType.Credentials,
|
||||
token,
|
||||
appId,
|
||||
url,
|
||||
expires,
|
||||
credentials
|
||||
);
|
||||
|
||||
return _currentSession;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new session using a static API token.
|
||||
/// </summary>
|
||||
/// <param name="url">The phpIPAM server URL.</param>
|
||||
/// <param name="appId">The API application ID.</param>
|
||||
/// <param name="token">The API token.</param>
|
||||
/// <returns>The created session.</returns>
|
||||
public static Session CreateSessionWithToken(string url, string appId, string token)
|
||||
{
|
||||
_currentSession = new Session(
|
||||
AuthType.Token,
|
||||
token,
|
||||
appId,
|
||||
url,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
return _currentSession;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the current session and clears session data.
|
||||
/// </summary>
|
||||
public static void CloseSession()
|
||||
{
|
||||
_currentSession = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an HttpClient with optional SSL bypass.
|
||||
/// </summary>
|
||||
/// <param name="ignoreSsl">Whether to ignore SSL certificate errors.</param>
|
||||
/// <param name="handler">Optional custom message handler for testing.</param>
|
||||
/// <returns>A configured HttpClient instance.</returns>
|
||||
public static HttpClient CreateHttpClient(bool ignoreSsl = false, HttpMessageHandler? handler = null)
|
||||
{
|
||||
if (handler != null)
|
||||
{
|
||||
return new HttpClient(handler);
|
||||
}
|
||||
|
||||
if (ignoreSsl)
|
||||
{
|
||||
var sslHandler = new HttpClientHandler
|
||||
{
|
||||
ServerCertificateCustomValidationCallback = (_, _, _, _) => true
|
||||
};
|
||||
return new HttpClient(sslHandler);
|
||||
}
|
||||
|
||||
return new HttpClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the plain text password from a PSCredential object.
|
||||
/// </summary>
|
||||
private static string GetPasswordString(PSCredential credential)
|
||||
{
|
||||
var ptr = Marshal.SecureStringToBSTR(credential.Password);
|
||||
try
|
||||
{
|
||||
return Marshal.PtrToStringBSTR(ptr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.ZeroFreeBSTR(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
23
classlib/IsExternalInit.cs
Normal file
23
classlib/IsExternalInit.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
// This file provides the IsExternalInit type required for using C# 9 records
|
||||
// in projects targeting .NET Standard 2.1 or earlier.
|
||||
|
||||
#if !NET5_0_OR_GREATER
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
using System.ComponentModel;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved to be used by the compiler for tracking metadata.
|
||||
/// This class should not be used by developers in source code.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal static class IsExternalInit
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
35
classlib/class/address.cs
Normal file
35
classlib/class/address.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an IP address entry in phpIPAM.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Address(
|
||||
int Id,
|
||||
int SubnetId,
|
||||
string Ip,
|
||||
bool IsGateway,
|
||||
string Description,
|
||||
string Hostname,
|
||||
string MAC,
|
||||
string Owner,
|
||||
int TagId,
|
||||
int DeviceId,
|
||||
string Location,
|
||||
string Port,
|
||||
string Note,
|
||||
DateTime? LastSeen,
|
||||
bool ExcludePing,
|
||||
bool PTRIgnore,
|
||||
int PTR,
|
||||
string FirewallAddressObject,
|
||||
DateTime? EditDate,
|
||||
int CustomerId,
|
||||
Dictionary<string, object>? ExtendedData = null
|
||||
)
|
||||
{
|
||||
public override string ToString() => Ip;
|
||||
}
|
||||
17
classlib/class/domain.cs
Normal file
17
classlib/class/domain.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an L2 domain in phpIPAM.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Domain(
|
||||
int Id,
|
||||
string Name,
|
||||
string Description,
|
||||
string Sections
|
||||
)
|
||||
{
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
35
classlib/class/nameserver.cs
Normal file
35
classlib/class/nameserver.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a nameserver configuration in phpIPAM.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Nameserver
|
||||
{
|
||||
public int Id { get; }
|
||||
public string Name { get; }
|
||||
public string[] NameServers { get; }
|
||||
public string Description { get; }
|
||||
public string Permissions { get; }
|
||||
public DateTime? EditDate { get; }
|
||||
|
||||
public Nameserver(
|
||||
int id,
|
||||
string name,
|
||||
string nameServers,
|
||||
string description,
|
||||
string permissions,
|
||||
DateTime? editDate)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
NameServers = nameServers?.Split(';', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
|
||||
Description = description;
|
||||
Permissions = permissions;
|
||||
EditDate = editDate;
|
||||
}
|
||||
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
27
classlib/class/section.cs
Normal file
27
classlib/class/section.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a section in phpIPAM that organizes subnets.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Section(
|
||||
int Id,
|
||||
string Name,
|
||||
string Description,
|
||||
int MasterSectionId,
|
||||
string Permissions,
|
||||
bool StrictMode,
|
||||
string SubnetOrdering,
|
||||
int Order,
|
||||
DateTime? EditDate,
|
||||
bool ShowSubnet,
|
||||
bool ShowVlan,
|
||||
bool ShowVRF,
|
||||
bool ShowSupernetOnly,
|
||||
int DNSId
|
||||
)
|
||||
{
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
27
classlib/class/session.cs
Normal file
27
classlib/class/session.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an authenticated session with phpIPAM API.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Session(
|
||||
AuthType AuthType,
|
||||
string Token,
|
||||
string AppID,
|
||||
string URL,
|
||||
DateTime? Expires,
|
||||
object? Credentials
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the current authentication token.
|
||||
/// </summary>
|
||||
public string Token { get; set; } = Token;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the token expiration time.
|
||||
/// </summary>
|
||||
public DateTime? Expires { get; set; } = Expires;
|
||||
}
|
||||
51
classlib/class/subnet.cs
Normal file
51
classlib/class/subnet.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a subnet/network in phpIPAM.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Subnetwork(
|
||||
int Id,
|
||||
string Subnet,
|
||||
int Mask,
|
||||
int SectionId,
|
||||
string Description,
|
||||
string LinkedSubnet,
|
||||
string FirewallAddressObject,
|
||||
int VrfId,
|
||||
int MasterSubnetId,
|
||||
bool AllowRequests,
|
||||
int VlanId,
|
||||
bool ShowName,
|
||||
int DeviceId,
|
||||
string Permissions,
|
||||
bool PingSubnet,
|
||||
bool DiscoverSubnet,
|
||||
bool ResolveDNS,
|
||||
bool DNSRecursive,
|
||||
bool DNSRecords,
|
||||
int NameserverId,
|
||||
bool ScanAgent,
|
||||
bool IsFolder,
|
||||
bool IsFull,
|
||||
bool IsPool,
|
||||
int TagId,
|
||||
int Threshold,
|
||||
int LocationId,
|
||||
DateTime? EditDate,
|
||||
DateTime? LastScan,
|
||||
DateTime? LastDiscovery,
|
||||
object Calculation,
|
||||
Dictionary<string, object>? ExtendedData = null
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the subnet in CIDR notation (e.g., "192.168.1.0/24").
|
||||
/// </summary>
|
||||
public string CIDR => $"{Subnet}/{Mask}";
|
||||
|
||||
public override string ToString() => CIDR;
|
||||
}
|
||||
21
classlib/class/tag.cs
Normal file
21
classlib/class/tag.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an address tag in phpIPAM.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Tag(
|
||||
int Id,
|
||||
string Type,
|
||||
bool ShowTag,
|
||||
string BackgroundColor,
|
||||
string ForegroundColor,
|
||||
string Compress,
|
||||
string Locked,
|
||||
bool UpdateTag
|
||||
)
|
||||
{
|
||||
public override string ToString() => Type;
|
||||
}
|
||||
27
classlib/class/vlan.cs
Normal file
27
classlib/class/vlan.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a VLAN in phpIPAM.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Vlan(
|
||||
int Id,
|
||||
int DomainId,
|
||||
string Name,
|
||||
int Number,
|
||||
string Description,
|
||||
DateTime? EditDate,
|
||||
int CustomerId,
|
||||
Dictionary<string, object>? ExtendedData = null
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
/// Alias for Id to maintain API compatibility.
|
||||
/// </summary>
|
||||
public int VlanId => Id;
|
||||
|
||||
public override string ToString() => Number.ToString();
|
||||
}
|
||||
21
classlib/class/vrf.cs
Normal file
21
classlib/class/vrf.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a VRF (Virtual Routing and Forwarding) instance in phpIPAM.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed record Vrf(
|
||||
int Id,
|
||||
string Name,
|
||||
string RouteDistinguisher,
|
||||
string Description,
|
||||
string Sections,
|
||||
DateTime? EditDate,
|
||||
Dictionary<string, object>? ExtendedData = null
|
||||
)
|
||||
{
|
||||
public override string ToString() => Name;
|
||||
}
|
||||
18
classlib/classlib.csproj
Normal file
18
classlib/classlib.csproj
Normal file
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AssemblyName>ps.ipam</AssemblyName>
|
||||
<RootNamespace>PS.IPAM</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
22
classlib/enum/SessionStatus.cs
Normal file
22
classlib/enum/SessionStatus.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the current status of an API session.
|
||||
/// </summary>
|
||||
public enum SessionStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// No session exists or no token is available.
|
||||
/// </summary>
|
||||
NoSession,
|
||||
|
||||
/// <summary>
|
||||
/// The session token has expired.
|
||||
/// </summary>
|
||||
Expired,
|
||||
|
||||
/// <summary>
|
||||
/// The session is valid and ready for use.
|
||||
/// </summary>
|
||||
Valid
|
||||
}
|
||||
20
classlib/enum/authType.cs
Normal file
20
classlib/enum/authType.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the authentication method for phpIPAM API.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum AuthType
|
||||
{
|
||||
/// <summary>
|
||||
/// Authentication using username and password credentials.
|
||||
/// </summary>
|
||||
Credentials,
|
||||
|
||||
/// <summary>
|
||||
/// Authentication using a static API token.
|
||||
/// </summary>
|
||||
Token
|
||||
}
|
||||
19
classlib/enum/controllers.cs
Normal file
19
classlib/enum/controllers.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the main API controllers in phpIPAM.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum ApiController
|
||||
{
|
||||
User,
|
||||
Vlan,
|
||||
Subnets,
|
||||
Addresses,
|
||||
Sections,
|
||||
Vrf,
|
||||
L2Domains,
|
||||
Tools
|
||||
}
|
||||
21
classlib/enum/subcontrollers.cs
Normal file
21
classlib/enum/subcontrollers.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents sub-controllers/endpoints within main API controllers.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum ApiSubController
|
||||
{
|
||||
Nameservers,
|
||||
Tags,
|
||||
Devices,
|
||||
DeviceTypes,
|
||||
Vlans,
|
||||
Vrfs,
|
||||
ScanAgents,
|
||||
Locations,
|
||||
Nat,
|
||||
Racks
|
||||
}
|
||||
19
classlib/enum/types.cs
Normal file
19
classlib/enum/types.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace PS.IPAM;
|
||||
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the model types returned by the phpIPAM API.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public enum ModelType
|
||||
{
|
||||
Address,
|
||||
Domain,
|
||||
Section,
|
||||
Subnetwork,
|
||||
Nameserver,
|
||||
Tag,
|
||||
Vlan,
|
||||
Vrf
|
||||
}
|
||||
21
functions/private/ConvertTo-Hashtable.ps1
Normal file
21
functions/private/ConvertTo-Hashtable.ps1
Normal file
@@ -0,0 +1,21 @@
|
||||
function ConvertTo-Hashtable {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PSCustomObject]$InputObject
|
||||
)
|
||||
process {
|
||||
$_hashtable = @{}
|
||||
$InputObject | Get-Member -MemberType *Property | Where-Object {
|
||||
$_hashtable.($_.name) = $CustomFields.($_.name)
|
||||
}
|
||||
|
||||
Write-Output $_hashtable
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
function Invoke-PSIPAMRequest {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateSet("POST","GET","PATCH","DELETE")]
|
||||
[string]
|
||||
$Method,
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateSet("user","vlan","subnets","addresses","sections","vrf","l2domains","tools")]
|
||||
[string]
|
||||
$Controller,
|
||||
[parameter(Mandatory=$false)]
|
||||
[ValidateSet("nameservers")]
|
||||
[string]
|
||||
$SubController,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[ValidateScript({ $_ -is [Hashtable] -or $_ -is [PSCustomObject] })]
|
||||
$Params,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[array]
|
||||
$Identifiers
|
||||
)
|
||||
$_tokenStatus = Test-PSIPAMSession
|
||||
|
||||
if ($_tokenStatus -eq "NoToken") { throw "No session available!" }
|
||||
if ($_tokenStatus -eq "Expired") { Update-PSIPAMSession }
|
||||
|
||||
$Controller = $Controller.ToLower()
|
||||
|
||||
$_uri = "$($script:ipamURL)/api/$($script:ipamAppID)/$Controller"
|
||||
if ($SubController) { $_uri += "/$SubController" }
|
||||
if ($Identifiers) { $_uri += "/$($Identifiers -join '/')/" }
|
||||
|
||||
$_headers = @{
|
||||
"Accept" = "application/json"
|
||||
"Content-Type" = "application/json"
|
||||
"token" = $script:ipamToken
|
||||
}
|
||||
|
||||
$_arguments = @{
|
||||
Method = $Method
|
||||
Uri = $_uri
|
||||
Headers = $_headers
|
||||
}
|
||||
|
||||
if ($Method -match "POST|PATCH") {
|
||||
if ($Params -is [PSCustomObject]) {
|
||||
$_params = @{};
|
||||
$Params | Get-Member -MemberType *Property | Where-Object {
|
||||
$_params.($_.name) = $Params.($_.name)
|
||||
}
|
||||
} else { $_params = $Params }
|
||||
|
||||
$_arguments.Add("Body",($_params | ConvertTo-Json))
|
||||
}
|
||||
|
||||
$_response = Invoke-RestMethod @_arguments
|
||||
|
||||
if ($_response.code -match "20\d") {
|
||||
return $_response.data
|
||||
} else {
|
||||
throw ("Error - $($_response.code)")
|
||||
}
|
||||
}
|
||||
103
functions/private/Invoke-Request.ps1
Normal file
103
functions/private/Invoke-Request.ps1
Normal file
@@ -0,0 +1,103 @@
|
||||
function Invoke-Request {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[parameter(Mandatory=$true)]
|
||||
[ValidateSet("GET","POST","PATCH","DELETE")]
|
||||
[string]
|
||||
$Method,
|
||||
[parameter(Mandatory=$true)]
|
||||
[PS.IPAM.controllers]
|
||||
$Controller,
|
||||
[parameter(Mandatory=$false)]
|
||||
[PS.IPAM.types]
|
||||
$Type,
|
||||
[parameter(Mandatory=$false)]
|
||||
[PS.IPAM.subcontrollers]
|
||||
$SubController,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[ValidateScript({ $_ -is [Hashtable] -or $_ -is [PSCustomObject] })]
|
||||
$Params,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[array]
|
||||
$Identifiers
|
||||
)
|
||||
$_tokenStatus = Test-Session
|
||||
|
||||
if ($_tokenStatus -eq "NoToken") { throw "No session available!" }
|
||||
if ($_tokenStatus -eq "Expired") { Update-Session }
|
||||
|
||||
$_uri = "$($script:psipamSession.URL)/api/$($script:psipamSession.AppID)/$Controller"
|
||||
if ($null -ne $SubController) { $_uri += "/$SubController" }
|
||||
if ($null -ne $Identifiers) { $_uri += "/$($Identifiers -join '/')/" }
|
||||
|
||||
$_headers = @{ }
|
||||
switch ($script:psipamSession.AuthType) {
|
||||
"Credentials" { $_headers.Add("token", $script:psipamSession.Token) }
|
||||
"Token" { $_headers.Add("phpipam-token", $script:psipamSession.Token) }
|
||||
}
|
||||
|
||||
$_arguments = @{
|
||||
Method = $Method
|
||||
Uri = $_uri
|
||||
Headers = $_headers
|
||||
ContentType = "application/json"
|
||||
}
|
||||
|
||||
if ($Method -eq "POST" -or $Method -eq "PATCH") {
|
||||
if ($Params -is [PSCustomObject]) {
|
||||
$_params = @{};
|
||||
$Params | Get-Member -MemberType *Property | Where-Object {
|
||||
$_params.($_.name) = $Params.($_.name)
|
||||
}
|
||||
} else { $_params = $Params }
|
||||
|
||||
$_arguments.Add("Body",($_params | ConvertTo-Json))
|
||||
}
|
||||
|
||||
Write-Verbose -Message "Invoking web request to $($_uri), with method $($_arguments.Method), headers: $($_arguments.Headers)"
|
||||
|
||||
try {
|
||||
$_response = Invoke-RestMethod @_arguments
|
||||
}
|
||||
catch [System.Net.WebException] {
|
||||
switch ($_.Exception.Message) {
|
||||
"The remote server returned an error: (404) Not Found." { Write-Verbose -Message "Not found." }
|
||||
"The remote server returned an error: (400) Bad Request." { Write-Warning -Message "Bad Request." }
|
||||
Default { Write-Verbose -Message "Error occured while requesting api" }
|
||||
}
|
||||
}
|
||||
if (!$_response) { return $null }
|
||||
|
||||
if ($Type -is [PS.IPAM.types]) {
|
||||
switch ($Type) {
|
||||
"address" {
|
||||
$_paramList = @("id","subnetId","ip","is_gateway","description","hostname","mac","owner","tag","deviceId","location","port","note","lastSeen","excludePing","PTRignore","PTR","firewallAddressObject","editDate","customer_id")
|
||||
|
||||
$_response.data | ForEach-Object {
|
||||
New-Object -TypeName ([PS.IPAM.Address]) -ArgumentList (@(($_ | Select-Object $_paramList).psobject.properties.value) + ($_ | Select-Object -Property custom_* -ExcludeProperty 'custom_\*'))
|
||||
}
|
||||
}
|
||||
"vlan" {
|
||||
$_paramList = @("vlanId","domainId","name","number","description","editDate","customer_id","custom_fields")
|
||||
|
||||
$_response.data | ForEach-Object {
|
||||
New-Object -TypeName ([PS.IPAM.Vlan]) -ArgumentList (@(($_ | Select-Object $_paramList).psobject.properties.value) + ($_ | Select-Object -Property custom_* -ExcludeProperty 'custom_\*'))
|
||||
}
|
||||
}
|
||||
"subnetwork" {
|
||||
$_response.data | ForEach-Object {
|
||||
New-Object -TypeName ([PS.IPAM.Subnetwork]) -ArgumentList (@($_.psobject.properties.value[0..30]) + ($_ | Select-Object -Property custom_* -ExcludeProperty 'custom_\*'))
|
||||
}
|
||||
}
|
||||
"vrf" {
|
||||
$_response.data | ForEach-Object {
|
||||
New-Object -TypeName ([PS.IPAM.Vrf]) -ArgumentList (@($_.psobject.properties.value[0..5]) + ($_ | Select-Object -Property custom_* -ExcludeProperty 'custom_\*'))
|
||||
}
|
||||
}
|
||||
Default { $_response.data | ForEach-Object { New-Object -TypeName ("PS.IPAM.$Type") -ArgumentList $_.psobject.properties.value } }
|
||||
}
|
||||
|
||||
} else {
|
||||
$_response.data
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
function Test-PSIPAMSession {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
|
||||
)
|
||||
if ($script:ipamToken) {
|
||||
if ($script:ipamExpires -lt (Get-Date)) {
|
||||
return "Expired"
|
||||
} else {
|
||||
return "Valid"
|
||||
}
|
||||
} else {
|
||||
return "NoToken"
|
||||
}
|
||||
}
|
||||
19
functions/private/Test-Session.ps1
Normal file
19
functions/private/Test-Session.ps1
Normal file
@@ -0,0 +1,19 @@
|
||||
function Test-Session {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
|
||||
)
|
||||
if ($script:psipamSession) {
|
||||
if ($null -eq $script:psipamSession.Expires) {
|
||||
return "Valid"
|
||||
} else {
|
||||
if ($script:psipamSession.Expires -lt (Get-Date)) {
|
||||
return "Expired"
|
||||
} else {
|
||||
return "Valid"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "NoToken"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
function Update-PSIPAMSession {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[switch]
|
||||
$Force
|
||||
)
|
||||
$_tokenStatus = Test-PSIPAMSession
|
||||
if ($_tokenStatus -eq "NoToken") {
|
||||
throw "No session available!"
|
||||
}
|
||||
if ($_tokenStatus -eq "Valid") {
|
||||
return (Invoke-PSIPAMRequest -Method PATCH -Controller user).expires
|
||||
}
|
||||
if ($_tokenStatus -eq "Expired" -or $Force) {
|
||||
New-PSIPAMSession -URL $script:ipamURL -AppID $script:ipamAppID -Credentials $script:ipamCredentials
|
||||
return $script:ipamExpires
|
||||
}
|
||||
}
|
||||
18
functions/private/Update-Session.ps1
Normal file
18
functions/private/Update-Session.ps1
Normal file
@@ -0,0 +1,18 @@
|
||||
function Update-Session {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[switch]
|
||||
$Force
|
||||
)
|
||||
$_tokenStatus = Test-Session
|
||||
if ($_tokenStatus -eq "NoToken") {
|
||||
throw "No session available!"
|
||||
}
|
||||
if ($_tokenStatus -eq "Valid") {
|
||||
return (Invoke-Request -Method [ps.ipam.methods]::PATCH -Controller [ps.ipam.controllers]::user).expires
|
||||
}
|
||||
if ($_tokenStatus -eq "Expired" -or $Force) {
|
||||
New-Session -URL $script:psipamSession.URL -AppID $script:psipamSession.AppID -Credentials $script:psipamSession.Credentials
|
||||
return
|
||||
}
|
||||
}
|
||||
49
functions/public/Assign-Tag.ps1
Normal file
49
functions/public/Assign-Tag.ps1
Normal file
@@ -0,0 +1,49 @@
|
||||
function Assign-Tag {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Assign tag to address.
|
||||
|
||||
.PARAMETER Tag
|
||||
Tag object to assign.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Address]
|
||||
$AddressObject,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
Position=1
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Tag]
|
||||
$Tag
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::addresses
|
||||
Method = "PATCH"
|
||||
}
|
||||
$_id = $AddressObject.id
|
||||
$_tagid = $Tag.id
|
||||
|
||||
$_identifiers = @($_id)
|
||||
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
$_body = @{ }
|
||||
$_body.Add("tag", $_tagid)
|
||||
|
||||
$_params.Add("Params",$_body)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Assign-Tag
|
||||
20
functions/public/Close-Session.ps1
Normal file
20
functions/public/Close-Session.ps1
Normal file
@@ -0,0 +1,20 @@
|
||||
function Close-Session {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Removes (revokes) token.
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param()
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::user
|
||||
Method = "DELETE"
|
||||
}
|
||||
|
||||
Invoke-Request @_params
|
||||
|
||||
$script:psipamSession = $null
|
||||
}
|
||||
}
|
||||
Export-ModuleMember Close-Session
|
||||
124
functions/public/Get-Address.ps1
Normal file
124
functions/public/Get-Address.ps1
Normal file
@@ -0,0 +1,124 @@
|
||||
function Get-Address {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Returns address object.
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
[OutputType([PS.IPAM.address])]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByIP"
|
||||
)]
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=1,
|
||||
ParameterSetName="BySubnetId"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ipaddress]
|
||||
$IP,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByHostName"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$HostName,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByHostBase"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$HostBase,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByTag"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$TagId,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="BySubnetId"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$SubnetId,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="BySubnetCIDR"
|
||||
)]
|
||||
[ValidateScript({[ipaddress] $_.Split("/")[0] -and $_.Split("/")[1] -match "\d{1,2}"})]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$SubnetCIDR
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::addresses
|
||||
Method = "GET"
|
||||
Type = [PS.IPAM.types]::address
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers = @($id); break }
|
||||
"ByIP" { $_identifiers = ("search",$IP); break }
|
||||
"ByHostName" { $_identifiers = ("search_hostname",$HostName); break }
|
||||
"ByHostBase" { $_identifiers = ("search_hostbase",$HostBase); break }
|
||||
"ByTag" { $_identifiers = ("tags",$TagId,[PS.IPAM.controllers]::addresses); break }
|
||||
"BySubnetId" {
|
||||
if ($IP) {
|
||||
$_identifiers = ($IP,$SubnetId)
|
||||
} else {
|
||||
$_params.Item("Controller") = [PS.IPAM.controllers]::subnets
|
||||
$_identifiers = ($SubnetId,[PS.IPAM.controllers]::addresses)
|
||||
}
|
||||
break
|
||||
}
|
||||
"BySubnetCIDR" {
|
||||
$_params.Item("Controller") = [PS.IPAM.controllers]::subnets
|
||||
$_subnetId = (Get-Subnet -CIDR $SubnetCIDR).id
|
||||
if (!$_subnetId) { throw "Cannot find subnet!" }
|
||||
|
||||
$_identifiers = ($_subnetId,[PS.IPAM.controllers]::addresses)
|
||||
break
|
||||
}
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-Address
|
||||
56
functions/public/Get-FirstFreeIP.ps1
Normal file
56
functions/public/Get-FirstFreeIP.ps1
Normal file
@@ -0,0 +1,56 @@
|
||||
function Get-FirstFreeIP {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByCIDR"
|
||||
)]
|
||||
[ValidateScript({[ipaddress] $_.Split("/")[0] -and $_.Split("/")[1] -match "\d{1,2}"})]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$CIDR,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="BySubnetObject"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Subnetwork]
|
||||
$SubnetObject
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::subnets
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_subnetId = $Id; break }
|
||||
"ByCIDR" {
|
||||
$_subnetId = (Get-Subnet -CIDR $CIDR).id
|
||||
if (!$_subnetId) { throw "Cannot find subnet!" }
|
||||
break
|
||||
}
|
||||
"BySubnetObject" { $_subnetId = $SubnetObject.Id; break }
|
||||
}
|
||||
$_identifiers = @($_subnetId,"first_free")
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
return Invoke-Request @_params | Select-Object @{n="Ip";e={$_}}
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-FirstFreeIP
|
||||
29
functions/public/Get-L2Domain.ps1
Normal file
29
functions/public/Get-L2Domain.ps1
Normal file
@@ -0,0 +1,29 @@
|
||||
function Get-L2Domain {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
[OutputType([PS.IPAM.Domain])]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::l2domains
|
||||
Method = "GET"
|
||||
Type = [PS.IPAM.types]::Domain
|
||||
}
|
||||
|
||||
$_identifiers = @($Id)
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-L2Domain
|
||||
31
functions/public/Get-Nameserver.ps1
Normal file
31
functions/public/Get-Nameserver.ps1
Normal file
@@ -0,0 +1,31 @@
|
||||
function Get-Nameserver {
|
||||
[CmdletBinding(DefaultParameterSetName="NoParams")]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::tools
|
||||
SubController = [PS.IPAM.subcontrollers]::nameservers
|
||||
Method = "GET"
|
||||
Type = [PS.IPAM.types]::nameserver
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_nameserverId = $Id; break }
|
||||
}
|
||||
$_identifiers = @($_nameserverId)
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-Nameserver
|
||||
@@ -1,33 +0,0 @@
|
||||
function Get-PSIPAMFirstFreeIP {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByCIDR")]
|
||||
[ValidateScript({[ipaddress] $_.Split("/")[0] -and $_.Split("/")[1] -match "\d{1,2}"})]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$CIDR,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = "subnets"
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_subnetId = $Id }
|
||||
"ByCIDR" {
|
||||
$_subnetId = (Get-PSIPAMSubnet -CIDR $CIDR).id
|
||||
if (!$_subnetId) { throw "Cannot find subnet!" }
|
||||
}
|
||||
}
|
||||
$_identifiers = @($_subnetId,"first_free")
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
return Invoke-PSIPAMRequest @_params | Select-Object @{n="Ip";e={$_}}
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-PSIPAMFirstFreeIP
|
||||
@@ -1,26 +0,0 @@
|
||||
function Get-PSIPAML2Domain {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
[string[]]$visiblePropertiesList = @('Id','Name','Description')
|
||||
$visibleProperties = [System.Management.Automation.PSPropertySet]::new('DefaultDisplayPropertySet',$visiblePropertiesList)
|
||||
|
||||
$_params = @{
|
||||
Controller = "l2domains"
|
||||
Method = "GET"
|
||||
}
|
||||
$_identifiers = @($Id)
|
||||
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params | `
|
||||
Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $visibleProperties -PassThru
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-PSIPAML2Domain
|
||||
@@ -1,29 +0,0 @@
|
||||
function Get-PSIPAMNameserver {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
[string[]]$visiblePropertiesList = @('Id','Name','Address','Description')
|
||||
$visibleProperties = [System.Management.Automation.PSPropertySet]::new('DefaultDisplayPropertySet',$visiblePropertiesList)
|
||||
|
||||
$_params = @{
|
||||
Controller = "tools"
|
||||
SubController = "nameservers"
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_nameserverId = $Id }
|
||||
}
|
||||
$_identifiers = @($_nameserverId)
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params | Select-Object @{n="address";e={$_.namesrv1}},* | Select-Object -ExcludeProperty namesrv1 | `
|
||||
Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $visibleProperties -PassThru
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-PSIPAMNameserver
|
||||
@@ -1,32 +0,0 @@
|
||||
function Get-PSIPAMSection {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0,ParameterSetName="ByName")]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Name
|
||||
)
|
||||
process {
|
||||
[string[]]$visiblePropertiesList = @('Id','Name','Description')
|
||||
$visibleProperties = [System.Management.Automation.PSPropertySet]::new('DefaultDisplayPropertySet',$visiblePropertiesList)
|
||||
|
||||
$_params = @{
|
||||
Controller = "sections"
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers = @($Id) }
|
||||
"ByName" { $_identifiers = @($Name) }
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params | `
|
||||
Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $visibleProperties -PassThru
|
||||
}
|
||||
}
|
||||
Export-ModuleMember Get-PSIPAMSection
|
||||
@@ -1,129 +0,0 @@
|
||||
function Get-PSIPAMSubnet {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByCIDR")]
|
||||
[ValidateScript({[ipaddress] $_.Split("/")[0] -and $_.Split("/")[1] -match "\d{1,2}"})]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$CIDR,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="BySectionId")]
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=2,ParameterSetName="ByVlanNumber")]
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=1,ParameterSetName="ByVlanId")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$SectionId,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="BySectionName")]
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=3,ParameterSetName="ByVlanNumber")]
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=2,ParameterSetName="ByVlanId")]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$SectionName,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByVrfId")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$VrfId,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByVlanId")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$VlanId,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByVlanNumber")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$VlanNumber,
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=1,ParameterSetName="ByVlanNumber")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$VlanDomain,
|
||||
[parameter(Mandatory=$false,ParameterSetName="ByID")]
|
||||
[switch]
|
||||
$Slaves,
|
||||
[parameter(Mandatory=$false,ParameterSetName="ByID")]
|
||||
[switch]
|
||||
$Recurse
|
||||
)
|
||||
process {
|
||||
[string[]]$visiblePropertiesList = @('Id','Subnet','Mask','Description')
|
||||
$visibleProperties = [System.Management.Automation.PSPropertySet]::new('DefaultDisplayPropertySet',$visiblePropertiesList)
|
||||
|
||||
$_params = @{
|
||||
Controller = "subnets"
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByCIDR" {
|
||||
$_identifiers = @("cidr",$CIDR)
|
||||
}
|
||||
"ByID" {
|
||||
$_identifiers = @($Id)
|
||||
|
||||
if ($Slaves) {
|
||||
if ($Recurse) {
|
||||
$_identifiers += "slaves_recursive"
|
||||
} else {
|
||||
$_identifiers += "slaves"
|
||||
}
|
||||
}
|
||||
}
|
||||
"BySectionId" {
|
||||
$_params.Item("Controller") = "sections"
|
||||
$_sectionId = $SectionId
|
||||
|
||||
$_identifiers = @($_sectionId,"subnets")
|
||||
}
|
||||
"BySectionName" {
|
||||
$_params.Item("Controller") = "sections"
|
||||
$_sectionId = (Get-PSIPAMSection -Name $SectionName).id
|
||||
if (!$_sectionId) { throw "Cannot find section!" }
|
||||
|
||||
$_identifiers = @($_sectionId,"subnets")
|
||||
}
|
||||
"ByVrfId" {
|
||||
$_params.Item("Controller") = "vrf"
|
||||
$_vrfId = $VrfId
|
||||
|
||||
$_identifiers = @($_vrfId,"subnets")
|
||||
}
|
||||
"ByVlanId" {
|
||||
$_params.Item("Controller") = "vlan"
|
||||
$_vlanId = $VlanId
|
||||
if ($SectionId) { $_sectionId = $SectionId }
|
||||
if ($SectionName){ $_sectionId = (Get-PSIPAMSection -Name $SectionName).id }
|
||||
|
||||
$_identifiers = @($_vlanId,"subnets")
|
||||
|
||||
if ($_sectionId) { $_identifiers += $_sectionId }
|
||||
}
|
||||
"ByVlanNumber" {
|
||||
$_params.Item("Controller") = "vlan"
|
||||
$_vlans = Get-PSIPAMVlan -Number $VlanNumber
|
||||
if ($VlanDomain) { $_vlans = $_vlans | Where-Object {$_.domainId -eq $VlanDomain} }
|
||||
if ($SectionId) { $_sectionId = $SectionId }
|
||||
if ($SectionName){ $_sectionId = (Get-PSIPAMSection -Name $SectionName).id }
|
||||
|
||||
$_vlanId = $_vlans.vlanId
|
||||
|
||||
if ($_vlanid -is [System.Array]) { throw "More than one vLan with $VlanNumber number is present!" }
|
||||
if (!$_vlanId) { throw "Cannot find Vlan!"}
|
||||
|
||||
$_identifiers = @($_vlanId,"subnets")
|
||||
|
||||
if ($_sectionId) { $_identifiers += $_sectionId }
|
||||
}
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params | `
|
||||
Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $visibleProperties -PassThru
|
||||
}
|
||||
}
|
||||
Export-ModuleMember Get-PSIPAMSubnet
|
||||
@@ -1,33 +0,0 @@
|
||||
function Get-PSIPAMSubnetUsage {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByCIDR")]
|
||||
[ValidateScript({[ipaddress] $_.Split("/")[0] -and $_.Split("/")[1] -match "\d{1,2}"})]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$CIDR,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = "subnets"
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByCIDR" {
|
||||
$_subnetId = (Get-PSIPAMSubnet -CIDR $CIDR).id
|
||||
if (!$_subnetId) { throw "Cannot find subnet!" }
|
||||
}
|
||||
"ByID" { $_subnetId = $Id }
|
||||
}
|
||||
$_identifiers = @($_subnetId,"usage")
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
return Invoke-PSIPAMRequest @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-PSIPAMSubnetUsage
|
||||
@@ -1,26 +0,0 @@
|
||||
function Get-PSIPAMTags {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
[string[]]$visiblePropertiesList = @('Id','Name')
|
||||
$visibleProperties = [System.Management.Automation.PSPropertySet]::new('DefaultDisplayPropertySet',$visiblePropertiesList)
|
||||
|
||||
$_params = @{
|
||||
Controller = "addresses"
|
||||
Method = "GET"
|
||||
}
|
||||
$_identifiers = @("tags")
|
||||
if ($Id) { $_identifiers += $Id }
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params | `
|
||||
Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $visibleProperties -PassThru
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-PSIPAMTags
|
||||
@@ -1,45 +0,0 @@
|
||||
function Get-PSIPAMVlan {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByNumber")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Number,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByL2Domain")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$L2DomainId
|
||||
)
|
||||
process {
|
||||
[string[]]$visiblePropertiesList = @('Id','Name','Description')
|
||||
$visibleProperties = [System.Management.Automation.PSPropertySet]::new('DefaultDisplayPropertySet',$visiblePropertiesList)
|
||||
|
||||
$_params = @{
|
||||
Controller = "vlan"
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers = @($Id) }
|
||||
"ByNumber" { $_identifiers = @("search",$Number) }
|
||||
"ByL2Domain"{
|
||||
$_params.Item("Controller") = "l2domains"
|
||||
|
||||
$_l2domainId = $L2DomainId
|
||||
|
||||
$_identifiers = @($_l2domainId,"vlans")
|
||||
}
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params | Select-Object @{n="id";e={$_.vlanId}},* | Select-Object -ExcludeProperty vlanId | `
|
||||
Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $visibleProperties -PassThru
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-PSIPAMVlan
|
||||
@@ -1,26 +0,0 @@
|
||||
function Get-PSIPAMVrf {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
[string[]]$visiblePropertiesList = @('Id','Name','Description')
|
||||
$visibleProperties = [System.Management.Automation.PSPropertySet]::new('DefaultDisplayPropertySet',$visiblePropertiesList)
|
||||
|
||||
$_params = @{
|
||||
Controller = "vrf"
|
||||
Method = "GET"
|
||||
}
|
||||
if ($Id) { $_identifiers = @($Id) }
|
||||
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params | Select-Object @{n="id";e={$_.vrfId}},* | Select-Object -ExcludeProperty vrfId | `
|
||||
Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $visibleProperties -PassThru
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-PSIPAMVrf
|
||||
@@ -1,5 +1,5 @@
|
||||
function Get-PSIPAMAddress {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
function Get-Permissions {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
@@ -41,10 +41,10 @@ function Get-PSIPAMAddress {
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers = @($id) }
|
||||
"ByIP" { $_identifiers = ("search",$IP) }
|
||||
"ByHostName" { $_identifiers = ("search_hostname",$HostName) }
|
||||
"ByTag" { $_identifiers = ("tags",$TagId,"addresses") }
|
||||
"ByID" { $_identifiers = @($id); break }
|
||||
"ByIP" { $_identifiers = ("search",$IP); break }
|
||||
"ByHostName" { $_identifiers = ("search_hostname",$HostName); break }
|
||||
"ByTag" { $_identifiers = ("tags",$TagId,"addresses"); break }
|
||||
"BySubnetId" {
|
||||
if ($IP) {
|
||||
$_identifiers = ($IP,$SubnetId)
|
||||
@@ -52,19 +52,21 @@ function Get-PSIPAMAddress {
|
||||
$_params.Item("Controller") = "subnets"
|
||||
$_identifiers = ($SubnetId,"addresses")
|
||||
}
|
||||
break
|
||||
}
|
||||
"BySubnetCIDR" {
|
||||
$_params.Item("Controller") = "subnets"
|
||||
$_subnetId = (Get-PSIPAMSubnet -CIDR $SubnetCIDR).id
|
||||
$_subnetId = (Get-Subnet -CIDR $SubnetCIDR).id
|
||||
if (!$_subnetId) { throw "Cannot find subnet!" }
|
||||
|
||||
$_identifiers = ($_subnetId,"addresses")
|
||||
break
|
||||
}
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params | `
|
||||
Invoke-Request @_params | `
|
||||
Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $visibleProperties -PassThru
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-PSIPAMAddress
|
||||
Export-ModuleMember -Function Get-Permissions
|
||||
39
functions/public/Get-Section.ps1
Normal file
39
functions/public/Get-Section.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
function Get-Section {
|
||||
[CmdletBinding(DefaultParameterSetName="NoParams")]
|
||||
[OutputType([PS.IPAM.Section])]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByName"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Name
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::sections
|
||||
Method = "GET"
|
||||
Type = [PS.IPAM.types]::Section
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers = @($Id); break }
|
||||
"ByName" { $_identifiers = @($Name); break }
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember Get-Section
|
||||
211
functions/public/Get-Subnet.ps1
Normal file
211
functions/public/Get-Subnet.ps1
Normal file
@@ -0,0 +1,211 @@
|
||||
function Get-Subnet {
|
||||
[CmdletBinding(DefaultParameterSetName="NoParams")]
|
||||
[OutputType([PS.IPAM.Subnetwork])]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByCIDR"
|
||||
)]
|
||||
[ValidateScript({[ipaddress] $_.Split("/")[0] -and $_.Split("/")[1] -match "\d{1,2}"})]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$CIDR,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="BySectionId"
|
||||
)]
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=2,
|
||||
ParameterSetName="ByVlanNumber"
|
||||
)]
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=1,
|
||||
ParameterSetName="ByVlanId"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$SectionId,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="BySectionName"
|
||||
)]
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=3,
|
||||
ParameterSetName="ByVlanNumber"
|
||||
)]
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=2,
|
||||
ParameterSetName="ByVlanId"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$SectionName,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByVrfId"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$VrfId,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByVlanId"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$VlanId,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByVlanNumber"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$VlanNumber,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=1,
|
||||
ParameterSetName="ByVlanNumber"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$VlanDomainId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=1,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[switch]
|
||||
$Slaves,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=2,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[switch]
|
||||
$Recurse
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::subnets
|
||||
Method = "GET"
|
||||
Type = [PS.IPAM.types]::Subnetwork
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByCIDR" {
|
||||
$_identifiers = @("cidr",$CIDR); break
|
||||
}
|
||||
"ByID" {
|
||||
$_identifiers = @($Id)
|
||||
|
||||
if ($Slaves) {
|
||||
if ($Recurse) {
|
||||
$_identifiers += "slaves_recursive"
|
||||
} else {
|
||||
$_identifiers += "slaves"
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
"BySectionId" {
|
||||
$_params.Item("Controller") = "sections"
|
||||
$_sectionId = $SectionId
|
||||
|
||||
$_identifiers = @($_sectionId,"subnets")
|
||||
break
|
||||
}
|
||||
"BySectionName" {
|
||||
$_params.Item("Controller") = "sections"
|
||||
$_sectionId = (Get-Section -Name $SectionName).id
|
||||
if (!$_sectionId) { throw "Cannot find section!" }
|
||||
|
||||
$_identifiers = @($_sectionId,"subnets")
|
||||
break
|
||||
}
|
||||
"ByVrfId" {
|
||||
$_params.Item("Controller") = "vrf"
|
||||
$_vrfId = $VrfId
|
||||
|
||||
$_identifiers = @($_vrfId,"subnets")
|
||||
break
|
||||
}
|
||||
"ByVlanId" {
|
||||
$_params.Item("Controller") = "vlan"
|
||||
$_vlanId = $VlanId
|
||||
if ($SectionId) { $_sectionId = $SectionId }
|
||||
if ($SectionName){ $_sectionId = (Get-Section -Name $SectionName).id }
|
||||
|
||||
$_identifiers = @($_vlanId,"subnets")
|
||||
|
||||
if ($_sectionId) { $_identifiers += $_sectionId }
|
||||
break
|
||||
}
|
||||
"ByVlanNumber" {
|
||||
$_params.Item("Controller") = "vlan"
|
||||
$_vlans = Get-Vlan -Number $VlanNumber
|
||||
if ($VlanDomain) { $_vlans = $_vlans | Where-Object {$_.domainId -eq $VlanDomain} }
|
||||
if ($SectionId) { $_sectionId = $SectionId }
|
||||
if ($SectionName){ $_sectionId = (Get-Section -Name $SectionName).id }
|
||||
|
||||
$_vlanId = $_vlans.vlanId
|
||||
|
||||
if ($_vlanid -is [System.Array]) { throw "More than one vLan with $VlanNumber number is present!" }
|
||||
if (!$_vlanId) { throw "Cannot find Vlan!"}
|
||||
|
||||
$_identifiers = @($_vlanId,"subnets")
|
||||
|
||||
if ($_sectionId) { $_identifiers += $_sectionId }
|
||||
break
|
||||
}
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember Get-Subnet
|
||||
45
functions/public/Get-SubnetUsage.ps1
Normal file
45
functions/public/Get-SubnetUsage.ps1
Normal file
@@ -0,0 +1,45 @@
|
||||
function Get-SubnetUsage {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByCIDR"
|
||||
)]
|
||||
[ValidateScript({[ipaddress] $_.Split("/")[0] -and $_.Split("/")[1] -match "\d{1,2}"})]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$CIDR,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [ps.ipam.controllers]::subnets
|
||||
Method = "GET"
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByCIDR" {
|
||||
$_subnetId = (Get-Subnet -CIDR $CIDR).id
|
||||
if (!$_subnetId) { throw "Cannot find subnet!" }
|
||||
break
|
||||
}
|
||||
"ByID" { $_subnetId = $Id; break }
|
||||
}
|
||||
$_identifiers = @($_subnetId,"usage")
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
return Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-SubnetUsage
|
||||
76
functions/public/Get-Tag.ps1
Normal file
76
functions/public/Get-Tag.ps1
Normal file
@@ -0,0 +1,76 @@
|
||||
function Get-Tag {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Return address tag.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Return address tag by id, address object or subnetwork object. Or leave it empty at take all tags at once.
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName="NoParams")]
|
||||
[OutputType([PS.IPAM.Tag])]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByAddressObject"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Address]
|
||||
$AddressObject,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="BySubnetObject"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Subnetwork]
|
||||
$SubnetObject
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::addresses
|
||||
Method = "GET"
|
||||
Type = [PS.IPAM.types]::tag
|
||||
}
|
||||
$_identifiers = @("tags")
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers += $Id; break }
|
||||
"ByAddressObject" {
|
||||
if ($AddressObject.TagId) {
|
||||
$_identifiers += $AddressObject.TagId
|
||||
} else {
|
||||
return $null
|
||||
}
|
||||
break
|
||||
}
|
||||
"BySubnetObject" {
|
||||
if ($SubnetObject.TagId) {
|
||||
$_identifiers += $SubnetObject.TagId
|
||||
} else {
|
||||
return $null
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-Tag
|
||||
101
functions/public/Get-Vlan.ps1
Normal file
101
functions/public/Get-Vlan.ps1
Normal file
@@ -0,0 +1,101 @@
|
||||
function Get-Vlan {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Return vlan object.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Return vlan object by vlanId, vlan number, l2domainId (return all vlans in domain), subnet object or l2domain object
|
||||
|
||||
.PARAMETER Number
|
||||
Vlan tag
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName="NoParams")]
|
||||
[OutputType([PS.IPAM.Vlan])]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByNumber"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Number,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByL2Domain"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$L2DomainId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="BySubnetObject"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Subnetwork]
|
||||
$SubnetObject,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByDomainObject"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Domain]
|
||||
$DomainObject
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::vlan
|
||||
Method = "GET"
|
||||
Type = [PS.IPAM.types]::Vlan
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers = @($Id); break }
|
||||
"ByNumber" { $_identifiers = @("search",$Number); break }
|
||||
"ByL2Domain"{
|
||||
$_params.Item("Controller") = [PS.IPAM.controllers]::l2domains
|
||||
|
||||
$_l2domainId = $L2DomainId
|
||||
|
||||
$_identifiers = @($_l2domainId,[PS.IPAM.subcontrollers]::vlans)
|
||||
break
|
||||
}
|
||||
"BySubnetObject" {
|
||||
if ($SubnetObject.VlanId) {
|
||||
$_identifiers = @($SubnetObject.VlanId); break
|
||||
} else {
|
||||
return $null
|
||||
}
|
||||
}
|
||||
"DomainObject" {
|
||||
Get-Vlan -L2DomainId $DomainObject.Id
|
||||
}
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-Vlan
|
||||
38
functions/public/Get-Vrf.ps1
Normal file
38
functions/public/Get-Vrf.ps1
Normal file
@@ -0,0 +1,38 @@
|
||||
function Get-Vrf {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Returns VRF object.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Returns VRF by id. Or leave it empty to get all VRFs.
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName="NoParams")]
|
||||
[OutputType([PS.IPAM.Vrf])]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::vrf
|
||||
Method = "GET"
|
||||
Type = [PS.IPAM.types]::vrf
|
||||
}
|
||||
if ($Id) { $_identifiers = @($Id) }
|
||||
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Get-Vrf
|
||||
@@ -1,21 +1,78 @@
|
||||
function New-PSIPAMAddress {
|
||||
[CmdletBinding()]
|
||||
function New-Address {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Creates address object.
|
||||
|
||||
.PARAMETER SubnetId
|
||||
Id of subnet address belongs to.
|
||||
|
||||
.PARAMETER Ip
|
||||
IP address.
|
||||
|
||||
.PARAMETER Gateway
|
||||
Defines if address is presented as gateway.
|
||||
|
||||
.PARAMETER Description
|
||||
Address description.
|
||||
|
||||
.PARAMETER Hostname
|
||||
Address hostname.
|
||||
|
||||
.PARAMETER MAC
|
||||
Mac address.
|
||||
|
||||
.PARAMETER Owner
|
||||
Address owner.
|
||||
|
||||
.PARAMETER TagId
|
||||
Id of subnet address belongs to.
|
||||
|
||||
.PARAMETER PTRIgnore
|
||||
Controls if PTR should not be created.
|
||||
|
||||
.PARAMETER PTRId
|
||||
Id of PowerDNS PTR record.
|
||||
|
||||
.PARAMETER Note
|
||||
Note.
|
||||
|
||||
.PARAMETER ExcludePing
|
||||
Exclude this address from status update scans (ping).
|
||||
|
||||
.PARAMETER DeviceId
|
||||
Id of device address belongs to.
|
||||
|
||||
.PARAMETER Port
|
||||
Port.
|
||||
#>
|
||||
[OutputType([PS.IPAM.address])]
|
||||
[CmdletBinding(DefaultParameterSetName="BySubnetId")]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of subnet address belongs to",
|
||||
Position=0)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
Position=0,
|
||||
ParameterSetName="BySubnetId"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$SubnetId,
|
||||
[Parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="BySubnetObject"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[ps.ipam.subnetwork]
|
||||
$SubnetObject,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="IP address",
|
||||
Position=1)]
|
||||
[ValidateScript({[ipaddress] $_ })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
@@ -25,7 +82,6 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Defines if address is presented as gateway",
|
||||
Position=2)]
|
||||
[switch]
|
||||
$Gateway,
|
||||
@@ -33,7 +89,6 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Address description",
|
||||
Position=3)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
@@ -42,7 +97,6 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Address hostname",
|
||||
Position=4)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
@@ -51,7 +105,6 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Mac address",
|
||||
Position=5)]
|
||||
[ValidateScript({ $_.Replace(":","") -match "^$('([A-F0-9]{2})' * 6)$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
@@ -61,7 +114,6 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Address owner",
|
||||
Position=6)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
@@ -70,17 +122,14 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of subnet address belongs to",
|
||||
Position=7)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$TagId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Controls if PTR should not be created",
|
||||
Position=8)]
|
||||
[switch]
|
||||
$PTRIgnore,
|
||||
@@ -88,17 +137,14 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of PowerDNS PTR record",
|
||||
Position=7)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$PTRId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Note",
|
||||
Position=10)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
@@ -107,7 +153,6 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Exclude this address from status update scans (ping)",
|
||||
Position=11)]
|
||||
[switch]
|
||||
$ExcludePing,
|
||||
@@ -115,34 +160,46 @@ function New-PSIPAMAddress {
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of device address belongs to",
|
||||
Position=12)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$DeviceId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Port",
|
||||
Position=13)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Port,
|
||||
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=14
|
||||
)]
|
||||
[ValidateScript({ $_ -is [Hashtable] -or $_ -is [PSCustomObject] })]
|
||||
$CustomFields
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = "addresses"
|
||||
Controller = [PS.IPAM.controllers]::addresses
|
||||
Method = "POST"
|
||||
}
|
||||
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"BySubnetId" {
|
||||
$_subnetId = $SubnetId
|
||||
break
|
||||
}
|
||||
"BySubnetObject" {
|
||||
$_subnetId = $SubnetObject.id
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
$_body = @{
|
||||
subnetId = $SubnetId
|
||||
subnetId = $_subnetId
|
||||
ip = $Ip
|
||||
}
|
||||
if ($Gateway) { $_body.Add("is_gateway", "1") }
|
||||
@@ -160,10 +217,7 @@ function New-PSIPAMAddress {
|
||||
|
||||
if ($CustomFields) {
|
||||
if ($CustomFields -is [PSCustomObject]) {
|
||||
$_customFields = @{};
|
||||
$CustomFields | Get-Member -MemberType *Property | Where-Object {
|
||||
$_customFields.($_.name) = $CustomFields.($_.name)
|
||||
}
|
||||
$_customFields = ConvertTo-Hashtable -InputObject $CustomFields
|
||||
} else { $_customFields = $CustomFields }
|
||||
|
||||
$_body = $_body + $_customFields
|
||||
@@ -171,12 +225,11 @@ function New-PSIPAMAddress {
|
||||
|
||||
$_params.Add("Params",$_body)
|
||||
|
||||
try {
|
||||
Invoke-PSIPAMRequest @_params
|
||||
}
|
||||
finally {
|
||||
Get-PSIPAMAddress -SubnetId $SubnetId -Ip $Ip
|
||||
$_result = Invoke-Request @_params
|
||||
|
||||
if ($_result) {
|
||||
Get-Address -SubnetId $SubnetId -Ip $Ip
|
||||
}
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function New-PSIPAMAddress
|
||||
Export-ModuleMember -Function New-Address
|
||||
@@ -1,4 +1,4 @@
|
||||
function New-PSIPAMFirstFreeIP {
|
||||
function New-FirstFreeIP {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[parameter(
|
||||
@@ -163,10 +163,10 @@ function New-PSIPAMFirstFreeIP {
|
||||
|
||||
$_params.Add("Params",$_body)
|
||||
|
||||
$_result = Invoke-PSIPAMRequest @_params
|
||||
$_result = Invoke-Request @_params
|
||||
if ($_result) {
|
||||
Get-PSIPAMAddress -SubnetId $SubnetId -IP $_result
|
||||
Get-Address -SubnetId $SubnetId -IP $_result
|
||||
}
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function New-PSIPAMFirstFreeIP
|
||||
Export-ModuleMember -Function New-FirstFreeIP
|
||||
@@ -1,37 +0,0 @@
|
||||
function New-PSIPAMSession {
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=0)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$URL,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=1)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$AppID,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,Position=2)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[pscredential]$Credentials
|
||||
)
|
||||
$_bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credentials.Password)
|
||||
$_password = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($_bstr)
|
||||
$_uri = "$URL/api/$AppID/user"
|
||||
$_auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$($Credentials.UserName):$_password"))
|
||||
$_headers = @{
|
||||
"Accept" = "application/json"
|
||||
"Content-Type" = "application/json"
|
||||
"Authorization" = "Basic $_auth"
|
||||
}
|
||||
|
||||
$_response = Invoke-RestMethod -Method Post -Uri $_uri -Headers $_headers -ErrorAction SilentlyContinue
|
||||
|
||||
if ($_response.success -eq $true) {
|
||||
$script:ipamAuth = $true
|
||||
$script:ipamToken = $_response.data.token
|
||||
$script:ipamAppID = $AppID
|
||||
$script:ipamURL = $URL
|
||||
$script:ipamCredentials = $Credentials
|
||||
$script:ipamExpires = Get-Date $_response.data.expires
|
||||
} else {
|
||||
$_response.error
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function New-PSIPAMSession
|
||||
111
functions/public/New-Session.ps1
Normal file
111
functions/public/New-Session.ps1
Normal file
@@ -0,0 +1,111 @@
|
||||
function New-Session {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Creates new session to phpIPAM instance.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Creates new session to phpIPAM instance by provided credentials or token.
|
||||
|
||||
.PARAMETER URL
|
||||
Base URL of phpIPAM instance.
|
||||
Example - http://ipam.example.com
|
||||
|
||||
.PARAMETER AppID
|
||||
API id (specified in phpIPAM api settings)
|
||||
|
||||
.PARAMETER Token
|
||||
User token foor authorization
|
||||
|
||||
.PARAMETER IgnoreSSL
|
||||
Ignore SSL errors
|
||||
|
||||
.OUTPUTS
|
||||
None. New-Session does not generate any output.
|
||||
#>
|
||||
[CmdletBinding(DefaultParameterSetName="Credentials")]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[validatescript({$_.startswith("http")})]
|
||||
[string]$URL,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=1
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$AppID,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=2,
|
||||
ParameterSetName="Credentials"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[pscredential]$Credentials,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=2,
|
||||
ParameterSetName="Token"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$Token,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=3
|
||||
)]
|
||||
[switch]$IgnoreSSL = $false
|
||||
)
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"Credentials" {
|
||||
$_bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credentials.Password)
|
||||
$_password = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($_bstr)
|
||||
$_uri = "$URL/api/$AppID/user"
|
||||
$_auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$($Credentials.UserName):$_password"))
|
||||
$_headers = @{
|
||||
"Accept" = "application/json"
|
||||
"Content-Type" = "application/json"
|
||||
"Authorization" = "Basic $_auth"
|
||||
}
|
||||
|
||||
$_response = Invoke-RestMethod -Method POST -Uri $_uri -Headers $_headers
|
||||
|
||||
if ($_response.success -ne $true) { return $_response.error }
|
||||
|
||||
$script:psipamSession = [PS.IPAM.Session]::new(
|
||||
[ps.ipam.authType]::credentials,
|
||||
$_response.data.token,
|
||||
$AppID,
|
||||
$URL,
|
||||
(Get-Date $_response.data.expires),
|
||||
$Credentials
|
||||
)
|
||||
break
|
||||
}
|
||||
"Token" {
|
||||
$script:psipamSession = [PS.IPAM.Session]::new(
|
||||
[ps.ipam.authType]::token,
|
||||
$Token,
|
||||
$AppID,
|
||||
$URL,
|
||||
$null,
|
||||
$null
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function New-Session
|
||||
@@ -1,12 +1,69 @@
|
||||
function New-PSIPAMSubnet {
|
||||
function New-Subnet {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Creates new subnetwork object.
|
||||
|
||||
.PARAMETER CIDR
|
||||
CIDR of subnet in dotted format (e.g 10.10.10.0/24).
|
||||
|
||||
.PARAMETER SectionId
|
||||
Section identifier.
|
||||
|
||||
.PARAMETER Description
|
||||
Subnet description.
|
||||
|
||||
.PARAMETER VlanId
|
||||
Assigns subnet to VLAN.
|
||||
|
||||
.PARAMETER VrfId
|
||||
Assigns subnet to VRF.
|
||||
|
||||
.PARAMETER MasterSubnetId
|
||||
Master subnet id for nested subnet.
|
||||
|
||||
.PARAMETER NameserverId
|
||||
Id of nameserver to attach to subnet.
|
||||
|
||||
.PARAMETER ShowName
|
||||
Controls weather subnet is displayed as IP address or Name in subnets menu.
|
||||
|
||||
.PARAMETER DNSRecursive
|
||||
Controls if PTR records should be created for subnet.
|
||||
|
||||
.PARAMETER DNSRecords
|
||||
Controls weather hostname DNS records are displayed.
|
||||
|
||||
.PARAMETER AllowRequests
|
||||
Controls if IP requests are allowed for subnet.
|
||||
|
||||
.PARAMETER ScanAgentId
|
||||
Controls which scanagent to use for subnet (default id 1).
|
||||
|
||||
.PARAMETER DiscoverSubnet
|
||||
Controls if new hosts should be discovered for new host scans.
|
||||
|
||||
.PARAMETER IsFull
|
||||
Marks subnet as used.
|
||||
|
||||
.PARAMETER TagId
|
||||
Assignes state (tag) to subnet (default: 1 Used).
|
||||
|
||||
.PARAMETER Threshold
|
||||
Subnet threshold.
|
||||
|
||||
.PARAMETER LocationId
|
||||
Location index.
|
||||
#>
|
||||
[OutputType([PS.IPAM.Subnetwork])]
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="CIDR of subnet in dotted format (e.g 10.10.10.0/24)",
|
||||
Position=0)]
|
||||
Position=0
|
||||
)]
|
||||
[ValidateScript({[ipaddress] $_.Split("/")[0] -and $_.Split("/")[1] -match "\d{1,2}"})]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
@@ -15,147 +72,154 @@ function New-PSIPAMSubnet {
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Section identifier",
|
||||
Position=1)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
Position=1
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$SectionId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Subnet description",
|
||||
Position=2)]
|
||||
Position=2
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Description,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Assigns subnet to VLAN",
|
||||
Position=3)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[string]
|
||||
Position=3
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$VlanId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Assigns subnet to VRF",
|
||||
Position=4)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[string]
|
||||
Position=4
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$VrfId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Master subnet id for nested subnet",
|
||||
Position=5)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[string]
|
||||
Position=5
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$MasterSubnetId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of nameserver to attach to subnet",
|
||||
Position=6)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[string]
|
||||
Position=6
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$NameserverId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Controls weather subnet is displayed as IP address or Name in subnets menu",
|
||||
Position=7)]
|
||||
Position=7
|
||||
)]
|
||||
[switch]
|
||||
$ShowName,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Controls if PTR records should be created for subnet",
|
||||
Position=8)]
|
||||
Position=8
|
||||
)]
|
||||
[switch]
|
||||
$DNSRecursive,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Controls weather hostname DNS records are displayed",
|
||||
Position=9)]
|
||||
Position=9
|
||||
)]
|
||||
[switch]
|
||||
$DNSRecords,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Controls if IP requests are allowed for subnet",
|
||||
Position=10)]
|
||||
Position=10
|
||||
)]
|
||||
[switch]
|
||||
$AllowRequests,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Controls which scanagent to use for subnet (default id 1)",
|
||||
Position=11)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[string]
|
||||
Position=11
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$ScanAgentId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Controls if new hosts should be discovered for new host scans",
|
||||
Position=12)]
|
||||
Position=12
|
||||
)]
|
||||
[switch]
|
||||
$DiscoverSubnet,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Marks subnet as used",
|
||||
Position=12)]
|
||||
Position=12
|
||||
)]
|
||||
[switch]
|
||||
$IsFull,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Assignes state (tag) to subnet (default: 1 Used)",
|
||||
Position=12)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[string]
|
||||
Position=12
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$TagId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Subnet threshold",
|
||||
Position=13)]
|
||||
[ValidateScript({ $_ -match "^\d+$" -and $_ -le 100 -and $_ -ge 1 })]
|
||||
Position=13
|
||||
)]
|
||||
[ValidateScript({ $_ -le 100 -and $_ -ge 1 })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Threshold,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Location index",
|
||||
Position=14)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[string]
|
||||
Position=14
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$LocationId,
|
||||
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=15
|
||||
)]
|
||||
[ValidateScript({ $_ -is [Hashtable] -or $_ -is [PSCustomObject] })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
$CustomFields
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = "subnets"
|
||||
Controller = [PS.IPAM.controllers]::subnets
|
||||
Method = "POST"
|
||||
}
|
||||
|
||||
@@ -182,10 +246,7 @@ function New-PSIPAMSubnet {
|
||||
|
||||
if ($CustomFields) {
|
||||
if ($CustomFields -is [PSCustomObject]) {
|
||||
$_customFields = @{};
|
||||
$CustomFields | Get-Member -MemberType *Property | Where-Object {
|
||||
$_customFields.($_.name) = $CustomFields.($_.name)
|
||||
}
|
||||
$_customFields = ConvertTo-Hashtable -InputObject $CustomFields
|
||||
} else { $_customFields = $CustomFields }
|
||||
|
||||
$_body = $_body + $_customFields
|
||||
@@ -193,10 +254,11 @@ function New-PSIPAMSubnet {
|
||||
|
||||
$_params.Add("Params",$_body)
|
||||
|
||||
$_result = Invoke-PSIPAMRequest @_params
|
||||
$_result = Invoke-Request @_params
|
||||
|
||||
if ($_result) {
|
||||
return Get-PSIPAMSubnet -CIDR $_result
|
||||
return Get-Subnet -CIDR $_result
|
||||
}
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function New-PSIPAMSubnet
|
||||
Export-ModuleMember -Function New-Subnet
|
||||
39
functions/public/Remove-Address.ps1
Normal file
39
functions/public/Remove-Address.ps1
Normal file
@@ -0,0 +1,39 @@
|
||||
function Remove-Address {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByID"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[int]
|
||||
$Id,
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
Position=0,
|
||||
ParameterSetName="ByAddressObject"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Address]
|
||||
$AddressObject
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = [PS.IPAM.controllers]::addresses
|
||||
Method = "DELETE"
|
||||
}
|
||||
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers = @($Id); break }
|
||||
"ByAddressObject" { $_identifiers = @($AddressObject.Id); break }
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-Request @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember Remove-Address
|
||||
@@ -1,35 +0,0 @@
|
||||
function Remove-PSIPAMAddress {
|
||||
[CmdletBinding(DefaultParameterSetName="ByID")]
|
||||
param (
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0,ParameterSetName="ByID")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Id,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0,ParameterSetName="ByIP")]
|
||||
[ValidateScript({[ipaddress] $_ })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$IP,
|
||||
[parameter(Mandatory=$true,ValueFromPipeline=$true,Position=1,ParameterSetName="ByIP")]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$SubnetId
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = "addresses"
|
||||
Method = "DELETE"
|
||||
}
|
||||
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_identifiers = @($Id) }
|
||||
"ByIP" { $_identifiers = @($IP,$SubnetId) }
|
||||
}
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
Invoke-PSIPAMRequest @_params
|
||||
}
|
||||
}
|
||||
Export-ModuleMember Remove-PSIPAMAddress
|
||||
@@ -1,150 +1,171 @@
|
||||
function Set-PSIPAMAddress {
|
||||
[CmdletBinding()]
|
||||
function Set-Address {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Edit address object.
|
||||
|
||||
.PARAMETER Id
|
||||
Id of subnet address belongs to.
|
||||
|
||||
.PARAMETER AddressObject
|
||||
Address object to edit.
|
||||
|
||||
.PARAMETER Gateway
|
||||
Defines if address is presented as gateway
|
||||
|
||||
.PARAMETER Description
|
||||
Address description.
|
||||
#>
|
||||
[OutputType([PS.IPAM.address])]
|
||||
[CmdletBinding(DefaultParameterSetName="ById")]
|
||||
param (
|
||||
[parameter(
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of subnet address belongs to",
|
||||
Position=0)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
Position=0,
|
||||
ParameterSetName="ById"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$Id,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
Mandatory=$true,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Defines if address is presented as gateway",
|
||||
Position=1)]
|
||||
Position=0,
|
||||
ParameterSetName="ByAddressObject"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[PS.IPAM.Address]
|
||||
$AddressObject,
|
||||
[parameter(
|
||||
Position=1
|
||||
)]
|
||||
[parameter(
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
ParameterSetName="ById"
|
||||
)]
|
||||
[bool]
|
||||
$Gateway,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
Position=2
|
||||
)]
|
||||
[parameter(
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Address description",
|
||||
Position=2)]
|
||||
ParameterSetName="ById"
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Description,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Address hostname",
|
||||
Position=3)]
|
||||
Position=3
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Hostname,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Mac address",
|
||||
Position=4)]
|
||||
Position=4
|
||||
)]
|
||||
[ValidateScript({ $_.Replace(":","") -match "^$('([A-F0-9]{2})' * 6)$" })]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$MAC,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Address owner",
|
||||
Position=5)]
|
||||
Position=5
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Owner,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of subnet address belongs to",
|
||||
Position=6)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
Position=6
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$TagId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Controls if PTR should not be created",
|
||||
Position=7)]
|
||||
Position=7
|
||||
)]
|
||||
[bool]
|
||||
$PTRIgnore,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of PowerDNS PTR record",
|
||||
Position=8)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
Position=8
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$PTRId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Note",
|
||||
Position=9)]
|
||||
Position=9
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Note,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Exclude this address from status update scans (ping)",
|
||||
Position=10)]
|
||||
Position=10
|
||||
)]
|
||||
[bool]
|
||||
$ExcludePing,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Id of device address belongs to",
|
||||
Position=11)]
|
||||
[ValidateScript({ $_ -match "^\d+$" })]
|
||||
Position=11
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
[int]
|
||||
$DeviceId,
|
||||
[parameter(
|
||||
Mandatory=$false,
|
||||
ValueFromPipeline=$true,
|
||||
ValueFromPipelineByPropertyName=$true,
|
||||
HelpMessage="Port",
|
||||
Position=12)]
|
||||
Position=12
|
||||
)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]
|
||||
$Port,
|
||||
|
||||
[parameter(Mandatory=$false,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
|
||||
[parameter(Mandatory=$false)]
|
||||
[ValidateScript({ $_ -is [Hashtable] -or $_ -is [PSCustomObject] })]
|
||||
$CustomFields
|
||||
)
|
||||
process {
|
||||
$_params = @{
|
||||
Controller = "addresses"
|
||||
Controller = [PS.IPAM.controllers]::addresses
|
||||
Method = "PATCH"
|
||||
}
|
||||
$_identifiers = @($Id)
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"ByID" { $_id = $Id; break }
|
||||
"ByAddressObject" { $_id = $AddressObject.id; break }
|
||||
}
|
||||
$_identifiers = @($_id)
|
||||
|
||||
$_params.Add("Identifiers",$_identifiers)
|
||||
|
||||
$_body = @{ }
|
||||
if ($Gateway) { $_body.Add("is_gateway", [int]$Gateway) }
|
||||
if ($Gateway) { $_body.Add("is_gateway", $Gateway) }
|
||||
if ($Description) { $_body.Add("description", $Description) }
|
||||
if ($Hostname) { $_body.Add("hostname", $Hostname) }
|
||||
if ($MAC) { $_body.Add("mac", $MAC) }
|
||||
if ($Owner) { $_body.Add("owner", $Owner) }
|
||||
if ($TagId) { $_body.Add("tag", $TagId) }
|
||||
if ($PTRIgnore) { $_body.Add("PTRignore", [int]$PTRIgnore) }
|
||||
if ($PTRIgnore) { $_body.Add("PTRignore", $PTRIgnore) }
|
||||
if ($PTRId) { $_body.add("PTR", $PTRId)}
|
||||
if ($Note) { $_body.Add("note", $Note) }
|
||||
if ($ExcludePing) { $_body.Add("excludePing", [int]$ExcludePing) }
|
||||
if ($ExcludePing) { $_body.Add("excludePing", $ExcludePing) }
|
||||
if ($DeviceId) { $_body.Add("deviceId", $DeviceId) }
|
||||
if ($Port) { $_body.Add("port", $Port) }
|
||||
|
||||
@@ -162,11 +183,11 @@ function Set-PSIPAMAddress {
|
||||
$_params.Add("Params",$_body)
|
||||
|
||||
try {
|
||||
Invoke-PSIPAMRequest @_params
|
||||
Invoke-Request @_params
|
||||
}
|
||||
finally {
|
||||
Get-PSIPAMAddress -Id $Id
|
||||
Get-Address -id $_id
|
||||
}
|
||||
}
|
||||
}
|
||||
Export-ModuleMember -Function Set-PSIPAMAddress
|
||||
Export-ModuleMember -Function Set-Address
|
||||
BIN
ps.ipam.psd1
BIN
ps.ipam.psd1
Binary file not shown.
198
types/types.ps1xml
Normal file
198
types/types.ps1xml
Normal file
@@ -0,0 +1,198 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Types>
|
||||
<Type>
|
||||
<Name>ps.ipam.address</Name>
|
||||
<Members>
|
||||
<MemberSet>
|
||||
<Name>PSStandardMembers</Name>
|
||||
<Members>
|
||||
<PropertySet>
|
||||
<Name>DefaultDisplayPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
<Name>Ip</Name>
|
||||
<Name>Hostname</Name>
|
||||
<Name>Description</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
<PropertySet>
|
||||
<Name>DefaultKeyPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
</Members>
|
||||
</MemberSet>
|
||||
</Members>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ps.ipam.tag</Name>
|
||||
<Members>
|
||||
<MemberSet>
|
||||
<Name>PSStandardMembers</Name>
|
||||
<Members>
|
||||
<PropertySet>
|
||||
<Name>DefaultDisplayPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
<Name>Type</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
<PropertySet>
|
||||
<Name>DefaultKeyPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
</Members>
|
||||
</MemberSet>
|
||||
</Members>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ps.ipam.domain</Name>
|
||||
<Members>
|
||||
<MemberSet>
|
||||
<Name>PSStandardMembers</Name>
|
||||
<Members>
|
||||
<PropertySet>
|
||||
<Name>DefaultDisplayPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
<Name>Name</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
<PropertySet>
|
||||
<Name>DefaultKeyPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
</Members>
|
||||
</MemberSet>
|
||||
</Members>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ps.ipam.section</Name>
|
||||
<Members>
|
||||
<MemberSet>
|
||||
<Name>PSStandardMembers</Name>
|
||||
<Members>
|
||||
<PropertySet>
|
||||
<Name>DefaultDisplayPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
<Name>Name</Name>
|
||||
<Name>MasterSectionId</Name>
|
||||
<Name>StrictMode</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
<PropertySet>
|
||||
<Name>DefaultKeyPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
</Members>
|
||||
</MemberSet>
|
||||
</Members>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ps.ipam.vlan</Name>
|
||||
<Members>
|
||||
<MemberSet>
|
||||
<Name>PSStandardMembers</Name>
|
||||
<Members>
|
||||
<PropertySet>
|
||||
<Name>DefaultDisplayPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
<Name>Name</Name>
|
||||
<Name>DomainId</Name>
|
||||
<Name>Number</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
<PropertySet>
|
||||
<Name>DefaultKeyPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
</Members>
|
||||
</MemberSet>
|
||||
</Members>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ps.ipam.vrf</Name>
|
||||
<Members>
|
||||
<MemberSet>
|
||||
<Name>PSStandardMembers</Name>
|
||||
<Members>
|
||||
<PropertySet>
|
||||
<Name>DefaultDisplayPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
<Name>Name</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
<PropertySet>
|
||||
<Name>DefaultKeyPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
</Members>
|
||||
</MemberSet>
|
||||
</Members>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ps.ipam.subnetwork</Name>
|
||||
<Members>
|
||||
<MemberSet>
|
||||
<Name>PSStandardMembers</Name>
|
||||
<Members>
|
||||
<PropertySet>
|
||||
<Name>DefaultDisplayPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
<Name>Subnet</Name>
|
||||
<Name>Mask</Name>
|
||||
<Name>SectionId</Name>
|
||||
<Name>Description</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
<PropertySet>
|
||||
<Name>DefaultKeyPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
</Members>
|
||||
</MemberSet>
|
||||
</Members>
|
||||
</Type>
|
||||
<Type>
|
||||
<Name>ps.ipam.nameserver</Name>
|
||||
<Members>
|
||||
<MemberSet>
|
||||
<Name>PSStandardMembers</Name>
|
||||
<Members>
|
||||
<PropertySet>
|
||||
<Name>DefaultDisplayPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
<Name>Name</Name>
|
||||
<Name>NameServers</Name>
|
||||
<Name>Description</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
<PropertySet>
|
||||
<Name>DefaultKeyPropertySet</Name>
|
||||
<ReferencedProperties>
|
||||
<Name>Id</Name>
|
||||
</ReferencedProperties>
|
||||
</PropertySet>
|
||||
</Members>
|
||||
</MemberSet>
|
||||
</Members>
|
||||
</Type>
|
||||
</Types>
|
||||
Reference in New Issue
Block a user