41 Commits

Author SHA1 Message Date
88e4e12e3d Merge pull request '2026-01-19-nah9' (#6) from 2026-01-19-nah9 into main
Some checks failed
CI/CD Pipeline / Build and Test (push) Failing after 34s
CI/CD Pipeline / Package Module (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
Reviewed-on: #6
2026-01-19 16:57:01 +03:00
6541cf18c0 Update Gitea CI workflow to use updated token secret for release creation
Some checks failed
CI/CD Pipeline / Build and Test (pull_request) Failing after 1m0s
CI/CD Pipeline / Package Module (pull_request) Has been skipped
CI/CD Pipeline / Create Release (pull_request) Has been skipped
2026-01-19 16:38:05 +03:00
0b237c6d1c Enhance unit tests for Address, Domain, Nameserver, Section, Session, Subnetwork, Tag, Vlan, and Vrf models; implement mock classes for HTTP requests and cmdlet testing. 2026-01-19 14:54:55 +03:00
40e3c31c6f Remove Jenkinsfile and add unit tests for various models including Address, Domain, Nameserver, Section, Session, Subnetwork, Tag, Vlan, and Vrf. Introduce mock classes for HTTP requests and cmdlet testing. 2026-01-19 14:46:09 +03:00
114267b1d5 Added assembly name and root namespace to project file; updated session and vlan classes with new properties; modified module manifest to reference DLL and updated exported cmdlets; corrected property name in address class. 2026-01-19 14:45:31 +03:00
010cce0fd8 Refactored subnet object methods and enhanced related documentation 2026-01-19 14:44:52 +03:00
f8f240e313 Updated subnet object handling and improved documentation 2026-01-19 14:44:10 +03:00
7f856b1d09 New address in subnet by subnet object 2022-12-30 14:43:46 +03:00
31b56c75e1 jenkinsfile content replace 2022-12-27 09:39:15 +03:00
7f0d14fc25 jenkinsfile 2022-12-27 09:31:54 +03:00
00975bb1c5 jenkinsfile 2022-12-27 09:31:33 +03:00
fb39efd493 Set-Address documented 2022-12-17 23:58:22 +03:00
e45d2665fa Documentation & fixes 2022-12-17 22:51:26 +03:00
2af591dbbf New-Address documentation 2022-12-17 14:53:48 +03:00
85e13dc150 Documented new-subnet 2022-12-17 14:36:41 +03:00
d1128997cc Added pscustomobject to hashtable converter 2022-12-17 02:11:13 +03:00
bc645fc0d8 Added Close-Session cmdlet 2022-12-17 01:51:55 +03:00
ced1dde708 Merge branch 'main' of https://git.arnike.ru/Arnike/ps.ipam 2022-12-17 01:37:51 +03:00
bad183aff4 Get-Nameserver fix 2022-12-17 01:37:50 +03:00
e456d7affe Remove-Address fix 2022-12-17 01:35:33 +03:00
Arnike
4c128f5864 Get-Subnet fix 2022-12-17 01:20:34 +03:00
Arnike
0913fc2069 content-type fix 2022-12-17 01:11:05 +03:00
ea9b760933 nameserver type fix. 2022-12-14 16:55:08 +03:00
833bb183eb Encoding fix 2022-12-14 16:00:00 +03:00
ed9d648074 Merge pull request 'Types-implement' (#5) from Types-implement into main
Reviewed-on: #5
2022-12-14 12:54:08 +00:00
ad9744bf56 version fix 2022-12-14 15:53:43 +03:00
1291bc0b69 CI\CD prep 2022-12-14 15:40:31 +03:00
b1c5feb73b Added nameserver type 2022-12-14 15:27:32 +03:00
6fb2e81142 Fixed subcontrollers 2022-12-14 15:26:43 +03:00
9912656752 Documentation 2022-12-14 13:22:13 +03:00
538d84305f subnetwork type fix 2022-12-14 11:23:27 +03:00
078beb8d3c Merge pull request 'Types-implement' (#4) from Types-implement into main
Reviewed-on: #4
2022-12-13 20:55:44 +00:00
9069989af3 Fixes 2022-12-12 18:58:13 +03:00
0742737f0d Added Assign-Tag cmdlet 2022-12-12 18:57:51 +03:00
5a34f03779 Fixes, added session class 2022-12-12 13:08:04 +03:00
7d0d1b53ae first working types 2022-12-06 17:20:45 +03:00
a1b03b81c0 replaced hardcoded text by enums in some functions 2022-12-05 17:48:20 +03:00
4fc6bac4b5 subnet type 2022-12-05 16:51:33 +03:00
c4b15d7387 enums 2022-12-05 15:29:03 +03:00
affbd18de2 classlib all types implemented 2022-12-05 14:08:59 +03:00
09cd00dc66 Base 2022-12-05 08:48:37 +03:00
96 changed files with 7420 additions and 720 deletions

121
.gitea/workflows/ci.yaml Normal file
View File

@@ -0,0 +1,121 @@
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 dependencies
run: dotnet restore
- 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@v4
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@v4
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@v4
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
View File

@@ -0,0 +1,4 @@
*.dll
bin
obj
.code-workspace

View File

@@ -27,6 +27,7 @@
[![License](https://img.shields.io/badge/license-GPL2+-blue.svg)](https://git.arnike.ru/Arnike/ps.ipam/src/branch/main/LICENSE)
![Powershell](https://img.shields.io/badge/powershell-v5.1+-blue.svg)
![PowerShell Gallery](https://img.shields.io/powershellgallery/dt/ps.ipam)
<h3 align="center">PS.IPAM</h3>

View File

@@ -0,0 +1,323 @@
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");
}
// 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",
controllers.addresses,
types.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",
controllers.addresses,
types.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",
controllers.addresses,
types.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",
controllers.addresses,
types.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",
controllers.subnets,
types.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",
controllers.addresses,
types.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",
controllers.subnets,
types.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",
controllers.addresses,
types.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",
controllers.addresses,
types.Address
);
// Assert
await action.Should().ThrowAsync<Exception>().WithMessage("No session available!");
}
}

View File

@@ -0,0 +1,103 @@
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);
}
}

View 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", controllers.addresses);
// Assert
await action.Should().ThrowAsync<Exception>().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", controllers.addresses, types.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", controllers.subnets, null, subcontrollers.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", controllers.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", controllers.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", controllers.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", controllers.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", controllers.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", controllers.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", controllers.addresses, types.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", controllers.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", controllers.addresses, types.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", controllers.subnets, types.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", controllers.vlan, types.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", controllers.subnets, types.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.GetCIDR().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", controllers.sections, types.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", controllers.addresses, types.Address, null, null, new[] { "1" });
// Assert
var address = (Address)result!;
address.ExtendedData.Should().NotBeNull();
var extendedData = (Dictionary<string, object>)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", controllers.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", controllers.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", controllers.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", controllers.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", controllers.addresses, types.Address);
// Assert
result.Should().BeNull();
}
}

View 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 TestSession_WhenNoSession_ReturnsNoToken()
{
// Arrange
SessionManager.CurrentSession = null;
// Act
var result = SessionManager.TestSession();
// Assert
result.Should().Be("NoToken");
}
[Fact]
public void TestSession_WhenSessionWithNullExpires_ReturnsValid()
{
// Arrange
var session = new Session(AuthType.token, "test-token", "app", "https://test.com", null, null);
SessionManager.CurrentSession = session;
// Act
var result = SessionManager.TestSession();
// Assert
result.Should().Be("Valid");
}
[Fact]
public void TestSession_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.TestSession();
// Assert
result.Should().Be("Valid");
}
[Fact]
public void TestSession_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.TestSession();
// Assert
result.Should().Be("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");
}
}

View 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) { }
}

View 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;
}
}
}

View File

@@ -0,0 +1,116 @@
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);
}
}

View 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);
}
}

View File

@@ -0,0 +1,82 @@
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_ReturnsArrayWithEmptyString()
{
// Arrange
var nameServersString = "";
// Act
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
// Assert
nameserver.NameServers.Should().HaveCount(1);
nameserver.NameServers[0].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();
}
}

View 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();
}
}

View File

@@ -0,0 +1,92 @@
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 ToString_ReturnsDefaultObjectString()
{
// Arrange
var session = new Session(AuthType.token, "token", "app", "https://test.com", null, null);
// Act
var result = session.ToString();
// Assert
result.Should().Contain("PS.IPAM.Session");
}
}

View File

@@ -0,0 +1,142 @@
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 GetCIDR_ReturnsCidrNotation(string subnet, int mask, string expectedCidr)
{
// Arrange
var subnetwork = CreateSubnetwork(subnet, mask);
// Act
var result = subnetwork.GetCIDR();
// 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_EqualsGetCIDR()
{
// Arrange
var subnetwork = CreateSubnetwork("172.20.0.0", 12);
// Act & Assert
subnetwork.ToString().Should().Be(subnetwork.GetCIDR());
}
private static Subnetwork CreateSubnetwork(string subnet, int mask)
{
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,
new object(), null
);
}
}

View File

@@ -0,0 +1,77 @@
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.BGColor.Should().Be(bgColor);
tag.FGColor.Should().Be(fgColor);
tag.Compress.Should().BeTrue();
tag.Locked.Should().BeFalse();
tag.UpdateTag.Should().Be(updateTag);
}
[Theory]
[InlineData("Yes", true)]
[InlineData("No", false)]
[InlineData("", false)]
[InlineData("yes", false)] // Case sensitive
[InlineData("true", false)] // Only "Yes" is true
public void StringToBool_ConvertsCorrectly(string input, bool expected)
{
// The StringToBool is private, so we test through the constructor
// Using Compress field which uses StringToBool
var tag = new Tag(1, "Test", false, "", "", input, "No", false);
tag.Compress.Should().Be(expected);
}
[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 Locked_WithYes_IsTrue()
{
// Arrange & Act
var tag = new Tag(1, "Test", false, "", "", "No", "Yes", false);
// Assert
tag.Locked.Should().BeTrue();
}
}

View 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();
}
}

View 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();
}
}

View 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;
}
}

View 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>

View File

@@ -0,0 +1,43 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet("Assign", "Tag")]
public class AssignTagCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0)]
[ValidateNotNullOrEmpty]
public Address? AddressObject { get; set; }
[Parameter(
Mandatory = true,
Position = 1)]
[ValidateNotNullOrEmpty]
public Tag? Tag { get; set; }
protected override void ProcessRecord()
{
try
{
var identifiers = new List<string> { AddressObject!.Id.ToString() };
var body = new Dictionary<string, object>
{
{ "tag", Tag!.Id }
};
RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, body, identifiers.ToArray())
.GetAwaiter().GetResult();
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "AssignTagError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,21 @@
namespace PS.IPAM.Cmdlets;
using System.Management.Automation;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Close, "Session")]
public class CloseSessionCmdlet : PSCmdlet
{
protected override void ProcessRecord()
{
try
{
RequestHelper.InvokeRequest("DELETE", controllers.user, null, null, null, null)
.GetAwaiter().GetResult();
SessionManager.CloseSession();
}
catch (System.Exception ex)
{
WriteError(new ErrorRecord(ex, "CloseSessionError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,162 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "Address", DefaultParameterSetName = "ByID")]
[OutputType(typeof(Address))]
public class GetAddressCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByID")]
[ValidateNotNullOrEmpty]
public int Id { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByIP")]
[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")]
[ValidateNotNullOrEmpty]
public string? HostName { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByHostBase")]
[ValidateNotNullOrEmpty]
public string? HostBase { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByTag")]
[ValidateNotNullOrEmpty]
public int? TagId { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetId")]
[ValidateNotNullOrEmpty]
public int? SubnetId { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetCIDR")]
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
[ValidateNotNullOrEmpty]
public string? SubnetCIDR { get; set; }
protected override void ProcessRecord()
{
try
{
var controller = controllers.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 = controllers.subnets;
identifiers.Add(SubnetId!.Value.ToString());
identifiers.Add("addresses");
}
break;
case "BySubnetCIDR":
controller = controllers.subnets;
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", SubnetCIDR! })
.GetAwaiter().GetResult();
if (subnet == null)
{
throw new Exception("Cannot find subnet!");
}
var subnetObj = subnet as Subnetwork;
identifiers.Add(subnetObj!.Id.ToString());
identifiers.Add("addresses");
break;
}
var result = RequestHelper.InvokeRequest("GET", controller, types.Address, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetAddressError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,79 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "FirstFreeIP", DefaultParameterSetName = "ByID")]
public class GetFirstFreeIPCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByCIDR")]
[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")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetObject")]
[ValidateNotNullOrEmpty]
public Subnetwork? SubnetObject { get; set; }
protected override void ProcessRecord()
{
try
{
int subnetId;
if (ParameterSetName == "ByCIDR")
{
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", CIDR! })
.GetAwaiter().GetResult();
if (subnet == null)
{
throw new Exception("Cannot find subnet!");
}
var subnetObj = subnet as Subnetwork;
subnetId = subnetObj!.Id;
}
else if (ParameterSetName == "BySubnetObject")
{
subnetId = SubnetObject!.Id;
}
else
{
subnetId = Id!.Value;
}
var identifiers = new List<string> { subnetId.ToString(), "first_free" };
var result = RequestHelper.InvokeRequest("GET", controllers.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));
}
}
}

View File

@@ -0,0 +1,54 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "L2Domain", DefaultParameterSetName = "ByID")]
[OutputType(typeof(Domain))]
public class GetL2DomainCmdlet : PSCmdlet
{
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByID")]
[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", controllers.l2domains, types.Domain, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetL2DomainError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,54 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "Nameserver", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Nameserver))]
public class GetNameserverCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByID")]
[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", controllers.tools, types.Nameserver, subcontrollers.nameservers, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetNameserverError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,148 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "Permissions")]
public class GetPermissionsCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByID")]
[ValidateNotNullOrEmpty]
public string? Id { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByIP")]
[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")]
[ValidateNotNullOrEmpty]
public string? HostName { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByTag")]
[ValidateNotNullOrEmpty]
public string? TagId { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetId")]
[ValidateNotNullOrEmpty]
public string? SubnetId { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetCIDR")]
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
[ValidateNotNullOrEmpty]
public string? SubnetCIDR { get; set; }
protected override void ProcessRecord()
{
try
{
var controller = controllers.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 = controllers.subnets;
identifiers.Add(SubnetId!);
identifiers.Add("addresses");
}
break;
case "BySubnetCIDR":
controller = controllers.subnets;
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", SubnetCIDR! })
.GetAwaiter().GetResult();
if (subnet == null)
{
throw new Exception("Cannot find subnet!");
}
var subnetObj = subnet as Subnetwork;
identifiers.Add(subnetObj!.Id.ToString());
identifiers.Add("addresses");
break;
}
var result = RequestHelper.InvokeRequest("GET", controller, null, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetPermissionsError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,65 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "Section", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Section))]
public class GetSectionCmdlet : PSCmdlet
{
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
Position = 0,
ParameterSetName = "ByID")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
Position = 0,
ParameterSetName = "ByName")]
[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", controllers.sections, types.Section, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetSectionError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,261 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "Subnet", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Subnetwork))]
public class GetSubnetCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByCIDR")]
[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")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
[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]
public int? SectionId { get; set; }
[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]
public string? SectionName { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByVrfId")]
[ValidateNotNullOrEmpty]
public int? VrfId { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByVlanId")]
[ValidateNotNullOrEmpty]
public int? VlanId { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByVlanNumber")]
[ValidateNotNullOrEmpty]
public int? VlanNumber { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 1,
ParameterSetName = "ByID")]
public SwitchParameter Slaves { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2,
ParameterSetName = "ByID")]
public SwitchParameter Recurse { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 1,
ParameterSetName = "ByVlanNumber")]
[ValidateNotNullOrEmpty]
public int? VlanDomainId { get; set; }
protected override void ProcessRecord()
{
try
{
var controller = controllers.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 = controllers.sections;
identifiers.Add(SectionId!.Value.ToString());
identifiers.Add("subnets");
break;
case "BySectionName":
controller = controllers.sections;
var section = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { SectionName! })
.GetAwaiter().GetResult();
if (section == null)
{
throw new Exception("Cannot find section!");
}
var sectionObj = section as Section;
identifiers.Add(sectionObj!.Id.ToString());
identifiers.Add("subnets");
break;
case "ByVrfId":
controller = controllers.vrf;
identifiers.Add(VrfId!.Value.ToString());
identifiers.Add("subnets");
break;
case "ByVlanId":
controller = controllers.vlan;
identifiers.Add(VlanId!.Value.ToString());
identifiers.Add("subnets");
if (SectionId.HasValue)
{
identifiers.Add(SectionId.Value.ToString());
}
else if (!string.IsNullOrEmpty(SectionName))
{
var section2 = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { SectionName })
.GetAwaiter().GetResult();
if (section2 != null)
{
var sectionObj2 = section2 as Section;
identifiers.Add(sectionObj2!.Id.ToString());
}
}
break;
case "ByVlanNumber":
controller = controllers.vlan;
var vlans = RequestHelper.InvokeRequest("GET", controllers.vlan, types.Vlan, null, null, new[] { "search", VlanNumber!.Value.ToString() })
.GetAwaiter().GetResult();
if (vlans == null)
{
throw new Exception("Cannot find Vlan!");
}
var vlanList = vlans as System.Collections.IEnumerable;
Vlan? foundVlan = null;
if (vlanList != null)
{
foreach (var v in vlanList)
{
if (v is Vlan vlan)
{
if (VlanDomainId.HasValue && vlan.DomainId != VlanDomainId.Value)
continue;
if (foundVlan != null)
{
throw new Exception($"More than one vLan with {VlanNumber} number is present!");
}
foundVlan = vlan;
}
}
}
if (foundVlan == null)
{
throw new Exception("Cannot find Vlan!");
}
identifiers.Add(foundVlan.Id.ToString());
identifiers.Add("subnets");
if (SectionId.HasValue)
{
identifiers.Add(SectionId.Value.ToString());
}
else if (!string.IsNullOrEmpty(SectionName))
{
var section3 = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { SectionName })
.GetAwaiter().GetResult();
if (section3 != null)
{
var sectionObj3 = section3 as Section;
identifiers.Add(sectionObj3!.Id.ToString());
}
}
break;
}
var result = RequestHelper.InvokeRequest("GET", controller, types.Subnetwork, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetSubnetError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,66 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "SubnetUsage", DefaultParameterSetName = "ByID")]
public class GetSubnetUsageCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByCIDR")]
[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")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
protected override void ProcessRecord()
{
try
{
int subnetId;
if (ParameterSetName == "ByCIDR")
{
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", CIDR! })
.GetAwaiter().GetResult();
if (subnet == null)
{
throw new Exception("Cannot find subnet!");
}
var subnetObj = subnet as Subnetwork;
subnetId = subnetObj!.Id;
}
else
{
subnetId = Id!.Value;
}
var identifiers = new List<string> { subnetId.ToString(), "usage" };
var result = RequestHelper.InvokeRequest("GET", controllers.subnets, null, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
if (result != null)
{
WriteObject(result);
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetSubnetUsageError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,98 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "Tag", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Tag))]
public class GetTagCmdlet : PSCmdlet
{
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByID")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByAddressObject")]
[ValidateNotNullOrEmpty]
public Address? AddressObject { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetObject")]
[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", controllers.addresses, types.Tag, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetTagError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,134 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "Vlan", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Vlan))]
public class GetVlanCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByID")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByNumber")]
[ValidateNotNullOrEmpty]
public int? Number { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByL2Domain")]
[ValidateNotNullOrEmpty]
public int? L2DomainId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetObject")]
[ValidateNotNullOrEmpty]
public Subnetwork? SubnetObject { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByDomainObject")]
[ValidateNotNullOrEmpty]
public Domain? DomainObject { get; set; }
protected override void ProcessRecord()
{
try
{
var controller = controllers.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 = controllers.l2domains;
identifiers.Add(L2DomainId!.Value.ToString());
identifiers.Add(subcontrollers.vlans.ToString());
break;
case "BySubnetObject":
if (SubnetObject != null && SubnetObject.VlanId > 0)
{
identifiers.Add(SubnetObject.VlanId.ToString());
}
else
{
return;
}
break;
case "ByDomainObject":
if (DomainObject != null)
{
var result = RequestHelper.InvokeRequest("GET", controllers.l2domains, types.Vlan, subcontrollers.vlans, null, new[] { DomainObject.Id.ToString() })
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
return;
}
var vlanResult = RequestHelper.InvokeRequest("GET", controller, types.Vlan, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
.GetAwaiter().GetResult();
if (vlanResult != null)
{
if (vlanResult is System.Collections.IEnumerable enumerable && !(vlanResult is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(vlanResult);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetVlanError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,54 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Get, "Vrf", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Vrf))]
public class GetVrfCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByID")]
[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", controllers.vrf, types.Vrf, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null)
.GetAwaiter().GetResult();
if (result != null)
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "GetVrfError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,219 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.New, "Address", DefaultParameterSetName = "BySubnetId")]
[OutputType(typeof(Address))]
public class NewAddressCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetId")]
[ValidateNotNullOrEmpty]
public int? SubnetId { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "BySubnetObject")]
[ValidateNotNullOrEmpty]
public Subnetwork? SubnetObject { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 1)]
[ValidateNotNullOrEmpty]
public string IP { get; set; } = string.Empty;
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2)]
public SwitchParameter Gateway { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 3)]
public string? Description { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 4)]
public string? Hostname { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 5)]
public string? MAC { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 6)]
public string? Owner { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 7)]
public int? TagId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 8)]
public SwitchParameter PTRIgnore { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 7)]
public int? PTRId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 10)]
public string? Note { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 11)]
public SwitchParameter ExcludePing { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public int? DeviceId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 13)]
public string? Port { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 14)]
public object? CustomFields { get; set; }
protected override void ProcessRecord()
{
try
{
int actualSubnetId;
if (ParameterSetName == "BySubnetObject")
{
actualSubnetId = SubnetObject!.Id;
}
else
{
actualSubnetId = SubnetId!.Value;
}
var body = new Dictionary<string, object>
{
{ "subnetId", actualSubnetId },
{ "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;
if (CustomFields != null)
{
var customDict = ConvertCustomFields(CustomFields);
foreach (var kvp in customDict)
{
body[kvp.Key] = kvp.Value;
}
}
var result = RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, body, null)
.GetAwaiter().GetResult();
if (result != null)
{
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "search", IP })
.GetAwaiter().GetResult();
if (address != null)
{
WriteObject(address);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "NewAddressError", ErrorCategory.InvalidOperation, null));
}
}
private Dictionary<string, object> ConvertCustomFields(object customFields)
{
var dict = new Dictionary<string, object>();
if (customFields is PSObject psobj)
{
foreach (var prop in psobj.Properties)
{
dict[prop.Name] = prop.Value ?? new object();
}
}
else if (customFields is Dictionary<string, object> dictObj)
{
return dictObj;
}
return dict;
}
}

View File

@@ -0,0 +1,190 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.New, "FirstFreeIP")]
[OutputType(typeof(Address))]
public class NewFirstFreeIPCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0)]
[ValidateNotNullOrEmpty]
public string SubnetId { get; set; } = string.Empty;
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2)]
public SwitchParameter Gateway { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 3)]
public string? Description { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 4)]
public string? Hostname { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 5)]
public string? MAC { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 6)]
public string? Owner { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 7)]
public string? TagId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 8)]
public SwitchParameter PTRIgnore { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 9)]
public string? PTRId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 10)]
public string? Note { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 11)]
public SwitchParameter ExcludePing { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public string? DeviceId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 13)]
public string? Port { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
public object? CustomFields { get; set; }
protected override void ProcessRecord()
{
try
{
var identifiers = new List<string> { "first_free" };
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;
if (CustomFields != null)
{
var customDict = ConvertCustomFields(CustomFields);
foreach (var kvp in customDict)
{
body[kvp.Key] = kvp.Value;
}
}
var result = RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, body, identifiers.ToArray())
.GetAwaiter().GetResult();
if (result != null)
{
var ip = result.ToString();
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "search", ip })
.GetAwaiter().GetResult();
if (address != null)
{
WriteObject(address);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "NewFirstFreeIPError", ErrorCategory.InvalidOperation, null));
}
}
private Dictionary<string, object> ConvertCustomFields(object customFields)
{
var dict = new Dictionary<string, object>();
if (customFields is PSObject psobj)
{
foreach (var prop in psobj.Properties)
{
dict[prop.Name] = prop.Value ?? new object();
}
}
else if (customFields is Dictionary<string, object> dictObj)
{
return dictObj;
}
return dict;
}
}

View File

@@ -0,0 +1,81 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Management.Automation;
using System.Threading.Tasks;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.New, "Session", DefaultParameterSetName = "Credentials")]
public class NewSessionCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0)]
[ValidateNotNullOrEmpty]
[ValidatePattern("^https?://")]
public string URL { get; set; } = string.Empty;
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 1)]
[ValidateNotNullOrEmpty]
public string AppID { get; set; } = string.Empty;
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2,
ParameterSetName = "Credentials")]
[ValidateNotNullOrEmpty]
public PSCredential? Credentials { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2,
ParameterSetName = "Token")]
[ValidateNotNullOrEmpty]
public string? Token { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 3)]
public SwitchParameter IgnoreSSL { get; set; }
protected override void ProcessRecord()
{
try
{
Session session;
if (ParameterSetName == "Credentials" && Credentials != null)
{
session = SessionManager.CreateSessionWithCredentials(
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");
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "NewSessionError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,231 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.New, "Subnet")]
[OutputType(typeof(Subnetwork))]
public class NewSubnetCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0)]
[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)]
[ValidateNotNullOrEmpty]
public int SectionId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2)]
public string? Description { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 3)]
public int? VlanId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 4)]
public int? VrfId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 5)]
public int? MasterSubnetId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 6)]
public int? NameserverId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 7)]
public SwitchParameter ShowName { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 8)]
public SwitchParameter DNSRecursive { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 9)]
public SwitchParameter DNSRecords { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 10)]
public SwitchParameter AllowRequests { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 11)]
public int? ScanAgentId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public SwitchParameter DiscoverSubnet { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public SwitchParameter IsFull { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public int? TagId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 13)]
[ValidateRange(1, 100)]
public int? Threshold { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 14)]
public int? LocationId { get; set; }
[Parameter(
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 15)]
public object? CustomFields { get; set; }
protected override void ProcessRecord()
{
try
{
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;
if (CustomFields != null)
{
var customDict = ConvertCustomFields(CustomFields);
foreach (var kvp in customDict)
{
body[kvp.Key] = kvp.Value;
}
}
var result = RequestHelper.InvokeRequest("POST", controllers.subnets, null, null, body, null)
.GetAwaiter().GetResult();
if (result != null)
{
// Get the created subnet
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", CIDR })
.GetAwaiter().GetResult();
if (subnet != null)
{
WriteObject(subnet);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "NewSubnetError", ErrorCategory.InvalidOperation, null));
}
}
private Dictionary<string, object> ConvertCustomFields(object customFields)
{
var dict = new Dictionary<string, object>();
if (customFields is PSObject psobj)
{
foreach (var prop in psobj.Properties)
{
dict[prop.Name] = prop.Value ?? new object();
}
}
else if (customFields is Dictionary<string, object> dictObj)
{
return dictObj;
}
return dict;
}
}

View File

@@ -0,0 +1,51 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Remove, "Address", DefaultParameterSetName = "ByID")]
public class RemoveAddressCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
Position = 0,
ParameterSetName = "ByID")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByAddressObject")]
[ValidateNotNullOrEmpty]
public Address? AddressObject { get; set; }
protected override void ProcessRecord()
{
try
{
int addressId;
if (ParameterSetName == "ByID")
{
addressId = Id!.Value;
}
else
{
addressId = AddressObject!.Id;
}
var identifiers = new List<string> { addressId.ToString() };
RequestHelper.InvokeRequest("DELETE", controllers.addresses, null, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "RemoveAddressError", ErrorCategory.InvalidOperation, null));
}
}
}

View File

@@ -0,0 +1,186 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Set, "Address", DefaultParameterSetName = "ById")]
[OutputType(typeof(Address))]
public class SetAddressCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ById")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0,
ParameterSetName = "ByAddressObject")]
[ValidateNotNullOrEmpty]
public Address? AddressObject { get; set; }
[Parameter(
Position = 1,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = "ById")]
public bool? Gateway { get; set; }
[Parameter(
Position = 2,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = "ById")]
public string? Description { get; set; }
[Parameter(
Mandatory = false,
Position = 3)]
public string? Hostname { get; set; }
[Parameter(
Mandatory = false,
Position = 4)]
public string? MAC { get; set; }
[Parameter(
Mandatory = false,
Position = 5)]
public string? Owner { get; set; }
[Parameter(
Mandatory = false,
Position = 6)]
public int? TagId { get; set; }
[Parameter(
Mandatory = false,
Position = 7)]
public bool? PTRIgnore { get; set; }
[Parameter(
Mandatory = false,
Position = 8)]
public int? PTRId { get; set; }
[Parameter(
Mandatory = false,
Position = 9)]
public string? Note { get; set; }
[Parameter(
Mandatory = false,
Position = 10)]
public bool? ExcludePing { get; set; }
[Parameter(
Mandatory = false,
Position = 11)]
public int? DeviceId { get; set; }
[Parameter(
Mandatory = false,
Position = 12)]
public string? Port { get; set; }
[Parameter(
Mandatory = false)]
public object? CustomFields { get; set; }
protected override void ProcessRecord()
{
try
{
int addressId;
if (ParameterSetName == "ById")
{
addressId = Id!.Value;
}
else
{
addressId = AddressObject!.Id;
}
var identifiers = new List<string> { addressId.ToString() };
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;
if (CustomFields != null)
{
var customDict = ConvertCustomFields(CustomFields);
foreach (var kvp in customDict)
{
body[kvp.Key] = kvp.Value;
}
}
try
{
RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, body, identifiers.ToArray())
.GetAwaiter().GetResult();
}
finally
{
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
if (address != null)
{
WriteObject(address);
}
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "SetAddressError", ErrorCategory.InvalidOperation, null));
}
}
private Dictionary<string, object> ConvertCustomFields(object customFields)
{
var dict = new Dictionary<string, object>();
if (customFields is PSObject psobj)
{
foreach (var prop in psobj.Properties)
{
dict[prop.Name] = prop.Value ?? new object();
}
}
else if (customFields is Dictionary<string, object> dictObj)
{
return dictObj;
}
return dict;
}
}

View File

@@ -0,0 +1,164 @@
namespace PS.IPAM.Cmdlets;
using System;
using System.Collections.Generic;
using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Set, "Subnet")]
[OutputType(typeof(Subnetwork))]
public class SetSubnetCmdlet : PSCmdlet
{
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 0)]
[ValidateNotNullOrEmpty]
public int Id { get; set; }
[Parameter(
Mandatory = false)]
public string? Description { get; set; }
[Parameter(
Mandatory = false)]
public int? VlanId { get; set; }
[Parameter(
Mandatory = false)]
public int? VrfId { get; set; }
[Parameter(
Mandatory = false)]
public int? MasterSubnetId { get; set; }
[Parameter(
Mandatory = false)]
public int? NameserverId { get; set; }
[Parameter(
Mandatory = false)]
public SwitchParameter ShowName { get; set; }
[Parameter(
Mandatory = false)]
public SwitchParameter DNSRecursive { get; set; }
[Parameter(
Mandatory = false)]
public SwitchParameter DNSRecords { get; set; }
[Parameter(
Mandatory = false)]
public SwitchParameter AllowRequests { get; set; }
[Parameter(
Mandatory = false)]
public int? ScanAgentId { get; set; }
[Parameter(
Mandatory = false)]
public SwitchParameter DiscoverSubnet { get; set; }
[Parameter(
Mandatory = false)]
public SwitchParameter IsFull { get; set; }
[Parameter(
Mandatory = false)]
public int? TagId { get; set; }
[Parameter(
Mandatory = false)]
[ValidateRange(1, 100)]
public int? Threshold { get; set; }
[Parameter(
Mandatory = false)]
public int? LocationId { get; set; }
[Parameter(
Mandatory = false)]
public object? CustomFields { get; set; }
protected override void ProcessRecord()
{
try
{
var identifiers = new List<string> { Id.ToString() };
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;
if (CustomFields != null)
{
var customDict = ConvertCustomFields(CustomFields);
foreach (var kvp in customDict)
{
body[kvp.Key] = kvp.Value;
}
}
RequestHelper.InvokeRequest("PATCH", controllers.subnets, null, null, body, identifiers.ToArray())
.GetAwaiter().GetResult();
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
if (subnet != null)
{
WriteObject(subnet);
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "SetSubnetError", ErrorCategory.InvalidOperation, null));
}
}
private Dictionary<string, object> ConvertCustomFields(object customFields)
{
var dict = new Dictionary<string, object>();
if (customFields is PSObject psobj)
{
foreach (var prop in psobj.Properties)
{
dict[prop.Name] = prop.Value ?? new object();
}
}
else if (customFields is Dictionary<string, object> dictObj)
{
return dictObj;
}
return dict;
}
}

View File

@@ -0,0 +1,374 @@
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;
using PS.IPAM;
public static class RequestHelper
{
// Handler for testing - allows injecting a mock HTTP handler
public static HttpMessageHandler? TestHttpHandler { get; set; }
public static async Task<object?> InvokeRequest(
string method,
controllers controller,
types? type = null,
subcontrollers? subController = null,
object? parameters = null,
string[]? identifiers = null,
bool ignoreSsl = false)
{
var tokenStatus = SessionManager.TestSession();
if (tokenStatus == "NoToken")
{
throw new Exception("No session available!");
}
if (tokenStatus == "Expired")
{
await UpdateSession();
}
var session = SessionManager.CurrentSession;
if (session == null)
{
throw new Exception("No session available!");
}
var uri = $"{session.URL}/api/{session.AppID}/{controller}";
if (subController != null)
{
uri += $"/{subController}";
}
if (identifiers != null && identifiers.Length > 0)
{
uri += $"/{string.Join("/", identifiers)}/";
}
using var client = SessionManager.CreateHttpClient(ignoreSsl, TestHttpHandler);
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;
}
HttpResponseMessage? response = null;
try
{
if (method == "GET")
{
response = await client.GetAsync(uri);
}
else if (method == "POST")
{
var jsonContent = parameters != null ? JsonConvert.SerializeObject(parameters) : "{}";
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
response = await client.PostAsync(uri, content);
}
else if (method == "PATCH")
{
var jsonContent = parameters != null ? JsonConvert.SerializeObject(parameters) : "{}";
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
var request = new HttpRequestMessage(new HttpMethod("PATCH"), uri)
{
Content = content
};
response = await client.SendAsync(request);
}
else if (method == "DELETE")
{
response = await client.DeleteAsync(uri);
}
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;
}
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(responseContent);
if (jsonResponse == null)
{
return null;
}
if (type.HasValue)
{
return ConvertToTypedObjects(jsonResponse, type.Value);
}
return jsonResponse.data;
}
catch (HttpRequestException ex)
{
if (ex.Message.Contains("404"))
{
return null;
}
throw;
}
}
private static object? ConvertToTypedObjects(dynamic jsonResponse, types type)
{
if (jsonResponse?.data == null)
{
return null;
}
var data = jsonResponse.data;
if (data is JArray array)
{
return array.Select(item => ConvertSingleObject(item, type)).ToList();
}
else
{
return ConvertSingleObject(data, type);
}
}
private static object? ConvertSingleObject(dynamic item, types type)
{
var jobject = item as JObject;
if (jobject == null)
{
return null;
}
var customFields = new Dictionary<string, object>();
foreach (var prop in jobject.Properties())
{
if (prop.Name.StartsWith("custom_"))
{
customFields[prop.Name] = prop.Value?.ToObject<object>() ?? new object();
}
}
switch (type)
{
case types.Address:
return CreateAddress(jobject, customFields);
case types.Vlan:
return CreateVlan(jobject, customFields);
case types.Subnetwork:
return CreateSubnetwork(jobject, customFields);
case types.Vrf:
return CreateVrf(jobject, customFields);
case types.Section:
return CreateSection(jobject);
case types.Tag:
return CreateTag(jobject);
case types.Nameserver:
return CreateNameserver(jobject);
case types.Domain:
return CreateDomain(jobject);
default:
return jobject.ToObject<object>();
}
}
private static Address CreateAddress(JObject jobject, Dictionary<string, object> customFields)
{
return new Address(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["subnetId"]?.ToObject<int>() ?? 0,
jobject["ip"]?.ToString() ?? "",
jobject["is_gateway"]?.ToObject<bool>() ?? false,
jobject["description"]?.ToString() ?? "",
jobject["hostname"]?.ToString() ?? "",
jobject["mac"]?.ToString() ?? "",
jobject["owner"]?.ToString() ?? "",
jobject["tag"]?.ToObject<int>() ?? 0,
jobject["deviceId"]?.ToObject<int>() ?? 0,
jobject["location"]?.ToString() ?? "",
jobject["port"]?.ToString() ?? "",
jobject["note"]?.ToString() ?? "",
jobject["lastSeen"]?.ToObject<DateTime?>(),
jobject["excludePing"]?.ToObject<bool>() ?? false,
jobject["PTRignore"]?.ToObject<bool>() ?? false,
jobject["PTR"]?.ToObject<int>() ?? 0,
jobject["firewallAddressObject"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>(),
jobject["customer_id"]?.ToObject<int>() ?? 0,
customFields.Count > 0 ? customFields : null
);
}
private static Vlan CreateVlan(JObject jobject, Dictionary<string, object> customFields)
{
return new Vlan(
jobject["vlanId"]?.ToObject<int>() ?? 0,
jobject["domainId"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["number"]?.ToObject<int>() ?? 0,
jobject["description"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>(),
jobject["customer_id"]?.ToObject<int>() ?? 0,
customFields.Count > 0 ? customFields : null
);
}
private static Subnetwork CreateSubnetwork(JObject jobject, Dictionary<string, object> customFields)
{
var props = jobject.Properties().ToList();
return new Subnetwork(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["subnet"]?.ToString() ?? "",
jobject["mask"]?.ToObject<int>() ?? 0,
jobject["sectionId"]?.ToObject<int>() ?? 0,
jobject["description"]?.ToString() ?? "",
jobject["linked_subnet"]?.ToString() ?? "",
jobject["firewallAddressObject"]?.ToString() ?? "",
jobject["vrfId"]?.ToObject<int>() ?? 0,
jobject["masterSubnetId"]?.ToObject<int>() ?? 0,
jobject["allowRequests"]?.ToObject<bool>() ?? false,
jobject["vlanId"]?.ToObject<int>() ?? 0,
jobject["showName"]?.ToObject<bool>() ?? false,
jobject["deviceId"]?.ToObject<int>() ?? 0,
jobject["permissions"]?.ToString() ?? "",
jobject["pingSubnet"]?.ToObject<bool>() ?? false,
jobject["discoverSubnet"]?.ToObject<bool>() ?? false,
jobject["resolveDNS"]?.ToObject<bool>() ?? false,
jobject["DNSrecursive"]?.ToObject<bool>() ?? false,
jobject["DNSrecords"]?.ToObject<bool>() ?? false,
jobject["nameserverId"]?.ToObject<int>() ?? 0,
jobject["scanAgent"]?.ToObject<bool>() ?? false,
jobject["isFolder"]?.ToObject<bool>() ?? false,
jobject["isFull"]?.ToObject<bool>() ?? false,
jobject["isPool"]?.ToObject<bool>() ?? false,
jobject["state"]?.ToObject<int>() ?? 0,
jobject["threshold"]?.ToObject<int>() ?? 0,
jobject["location"]?.ToObject<int>() ?? 0,
jobject["editDate"]?.ToObject<DateTime?>(),
jobject["lastScan"]?.ToObject<DateTime?>(),
jobject["lastDiscovery"]?.ToObject<DateTime?>(),
jobject["calculation"]?.ToObject<object>() ?? new object(),
customFields.Count > 0 ? customFields : null
);
}
private static Vrf CreateVrf(JObject jobject, Dictionary<string, object> customFields)
{
return new Vrf(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["rd"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "",
jobject["sections"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>(),
customFields.Count > 0 ? customFields : null
);
}
private static Section CreateSection(JObject jobject)
{
return new Section(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "",
jobject["masterSection"]?.ToObject<int>() ?? 0,
jobject["permissions"]?.ToString() ?? "",
jobject["strictMode"]?.ToObject<bool>() ?? false,
jobject["subnetOrdering"]?.ToString() ?? "",
jobject["order"]?.ToObject<int>() ?? 0,
jobject["editDate"]?.ToObject<DateTime?>(),
jobject["showSubnet"]?.ToObject<bool>() ?? false,
jobject["showVlan"]?.ToObject<bool>() ?? false,
jobject["showVRF"]?.ToObject<bool>() ?? false,
jobject["showSupernetOnly"]?.ToObject<bool>() ?? false,
jobject["DNS"]?.ToObject<int>() ?? 0
);
}
private static Tag CreateTag(JObject jobject)
{
return new Tag(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["type"]?.ToString() ?? "",
jobject["showtag"]?.ToObject<bool>() ?? false,
jobject["bgcolor"]?.ToString() ?? "",
jobject["fgcolor"]?.ToString() ?? "",
jobject["compress"]?.ToString() ?? "",
jobject["locked"]?.ToString() ?? "",
jobject["updateTag"]?.ToObject<bool>() ?? false
);
}
private static Nameserver CreateNameserver(JObject jobject)
{
return new Nameserver(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["nameservers"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "",
jobject["permissions"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>()
);
}
private static Domain CreateDomain(JObject jobject)
{
return new Domain(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "",
jobject["sections"]?.ToString() ?? ""
);
}
private static async Task UpdateSession()
{
var session = SessionManager.CurrentSession;
if (session == null)
{
throw new Exception("No session available!");
}
var tokenStatus = SessionManager.TestSession();
if (tokenStatus == "Valid")
{
// Just refresh the token
var result = await InvokeRequest("PATCH", controllers.user, null, null, null, null);
// Token refresh doesn't return expires in the same format, so we'll skip updating expires
return;
}
if (tokenStatus == "Expired" && session.Credentials is PSCredential creds)
{
await SessionManager.CreateSessionWithCredentials(
session.URL,
session.AppID,
creds,
false
);
}
}
}

View File

@@ -0,0 +1,131 @@
namespace PS.IPAM.Helpers;
using System;
using System.Management.Automation;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using PS.IPAM;
public static class SessionManager
{
private static Session? _currentSession;
public static Session? CurrentSession
{
get => _currentSession;
set => _currentSession = value;
}
public static string TestSession()
{
if (_currentSession == null)
{
return "NoToken";
}
if (_currentSession.Expires == null)
{
return "Valid";
}
if (_currentSession.Expires < DateTime.Now)
{
return "Expired";
}
return "Valid";
}
public static async Task<Session> CreateSessionWithCredentials(
string url,
string appId,
PSCredential credentials,
bool ignoreSsl = false)
{
var uri = $"{url}/api/{appId}/user";
var auth = Convert.ToBase64String(
Encoding.UTF8.GetBytes($"{credentials.UserName}:{GetPassword(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 Exception(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;
}
public static Session CreateSessionWithToken(
string url,
string appId,
string token)
{
_currentSession = new Session(
AuthType.token,
token,
appId,
url,
null,
null
);
return _currentSession;
}
public static void CloseSession()
{
_currentSession = null;
}
private static string GetPassword(PSCredential credential)
{
var ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(credential.Password);
try
{
return System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
}
public static HttpClient CreateHttpClient(bool ignoreSsl = false, HttpMessageHandler? handler = null)
{
if (handler != null)
{
return new HttpClient(handler);
}
if (ignoreSsl)
{
var sslHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
};
return new HttpClient(sslHandler);
}
return new HttpClient();
}
}

77
classlib/class/address.cs Normal file
View File

@@ -0,0 +1,77 @@
namespace PS.IPAM;
using System;
[Serializable]
public class Address {
public int Id { get; }
public int SubnetId { get; }
public string Ip { get; }
public bool IsGateway { get; }
public string Description { get; }
public string Hostname { get; }
public string MAC { get; }
public string Owner { get; }
public int TagId { get; }
public int DeviceId { get; }
public string Location { get; }
public string Port { get; }
public string Note { get; }
public DateTime? LastSeen { get; }
public bool ExcludePing { get; }
public bool PTRignore { get; }
public int PTR { get; }
public string FirewallAddressObject { get; }
public DateTime? EditDate { get; }
public int CustomerId { get; }
public Object? ExtendedData { get; }
public Address(
int id,
int subnetId,
string ip,
bool is_gateway,
string description,
string hostname,
string mac,
string owner,
int tag,
int deviceId,
string location,
string port,
string note,
DateTime? lastSeen,
bool excludePing,
bool PTRignore,
int PTR,
string firewallAddressObject,
DateTime? editDate,
int customer_id,
Object? extendedData
) {
this.Id = id;
this.SubnetId = subnetId;
this.Ip = ip;
this.IsGateway = is_gateway;
this.Description = description;
this.Hostname = hostname;
this.MAC = mac;
this.Owner = owner;
this.TagId = tag;
this.DeviceId = deviceId;
this.Location = location;
this.Port = port;
this.Note = note;
this.LastSeen = lastSeen;
this.ExcludePing = excludePing;
this.PTRignore = PTRignore;
this.PTR = PTR;
this.FirewallAddressObject = firewallAddressObject;
this.EditDate = editDate;
this.CustomerId = customer_id;
this.ExtendedData = extendedData;
}
public override string ToString() {
return this.Ip;
}
}

27
classlib/class/domain.cs Normal file
View File

@@ -0,0 +1,27 @@
namespace PS.IPAM;
using System;
[Serializable]
public class Domain {
public int Id { get; }
public string Name { get; }
public string Description { get; }
public string Sections { get; }
public Domain (
int id,
string name,
string description,
string sections
) {
this.Id = id;
this.Name = name;
this.Description = description;
this.Sections = sections;
}
public override string ToString()
{
return this.Name;
}
}

View File

@@ -0,0 +1,28 @@
namespace PS.IPAM;
using System;
[Serializable]
public class 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
) {
this.Id = id;
this.Name = name;
this.NameServers = nameServers.Split(new char[] {';'});
this.Description = description;
this.Permissions = permissions;
this.EditDate = editDate;
}
}

57
classlib/class/section.cs Normal file
View File

@@ -0,0 +1,57 @@
namespace PS.IPAM;
using System;
[Serializable]
public class Section {
public int Id { get; }
public string Name { get; }
public string Description { get; }
public int MasterSectionId { get; }
public string Permissions { get; }
public bool StrictMode { get; }
public string SubnetOrdering { get; }
public int Order { get; }
public DateTime? EditDate { get; }
public bool ShowSubnet { get; }
public bool ShowVlan { get; }
public bool ShowVRF { get; }
public bool ShowSupernetOnly { get; }
public int DNSId { get; }
public 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
) {
this.Id = id;
this.Name = name;
this.Description = description;
this.MasterSectionId = masterSectionId;
this.Permissions = permissions;
this.StrictMode = strictMode;
this.SubnetOrdering = subnetOrdering;
this.Order = order;
this.EditDate = editDate;
this.ShowSubnet = showSubnet;
this.ShowVlan = showVlan;
this.ShowVRF = showVRF;
this.ShowSupernetOnly = showSupernetOnly;
this.DNSId = dnsId;
}
public override string ToString()
{
return this.Name;
}
}

33
classlib/class/session.cs Normal file
View File

@@ -0,0 +1,33 @@
namespace PS.IPAM;
using System;
using System.Management.Automation;
[Serializable]
public class Session {
public AuthType AuthType { get; }
public string Token { get; set; }
public string AppID { get; }
public string URL { get; }
public DateTime? Expires { get; set; }
public object? Credentials { get; }
public Session(
AuthType authType,
string token,
string appId,
string url,
DateTime? expires,
object? credentials
) {
AuthType = authType;
Token = token;
AppID = appId;
URL = url;
Expires = expires;
Credentials = credentials;
}
public override string ToString()
{
return base.ToString();
}
}

114
classlib/class/subnet.cs Normal file
View File

@@ -0,0 +1,114 @@
namespace PS.IPAM;
using System;
[Serializable]
public class Subnetwork {
public int Id { get; }
public string Subnet { get; }
public int Mask { get; }
public int SectionId { get; }
public string Description { get; }
public string LinkedSubnet { get; }
public string FirewallAddressObject { get; }
public int VrfId { get; }
public int MasterSubnetId { get; }
public bool AllowRequests { get; }
public int VlanId { get; }
public bool ShowName { get; }
public int DeviceId { get; }
public string Permissions { get; }
public bool PingSubnet { get; }
public bool DiscoverSubnet { get; }
public bool ResolveDNS { get; }
public bool DNSRecursive { get; }
public bool DNSRecords { get; }
public int NameserverId { get; }
public bool ScanAgent { get; }
public bool IsFolder { get; }
public bool IsFull { get; }
public bool IsPool { get; }
public int TagId { get; }
public int Threshold { get; }
public int LocationId { get; }
public DateTime? EditDate { get; }
public DateTime? LastScan { get; }
public DateTime? LastDiscovery { get; }
public Object Calculation { get; }
public Object? ExtendedData { get; }
public 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,
Object? custom_fields
) {
this.Id = id;
this.Subnet = subnet;
this.Mask = mask;
this.SectionId = sectionId;
this.Description = description;
this.LinkedSubnet = linkedSubnet;
this.FirewallAddressObject = firewallAddressObject;
this.VrfId = vrfId;
this.MasterSubnetId = masterSubnetId;
this.AllowRequests = allowRequests;
this.VlanId = vlanId;
this.ShowName = showName;
this.DeviceId = deviceId;
this.Permissions = permissions;
this.PingSubnet = pingSubnet;
this.DiscoverSubnet = discoverSubnet;
this.ResolveDNS = resolveDNS;
this.DNSRecursive = dnsRecursive;
this.DNSRecords = dnsRecords;
this.NameserverId = nameserverId;
this.ScanAgent = scanAgent;
this.IsFolder = isFolder;
this.IsFull = isFull;
this.IsPool = isPool;
this.TagId = tagId;
this.Threshold = threshold;
this.LocationId = locationId;
this.EditDate = editDate;
this.LastScan = lastScan;
this.LastDiscovery = lastDiscovery;
this.Calculation = calculation;
this.ExtendedData = custom_fields;
}
public string GetCIDR() {
return $"{this.Subnet}/{this.Mask}";
}
public override string ToString()
{
return this.GetCIDR();
}
}

45
classlib/class/tag.cs Normal file
View File

@@ -0,0 +1,45 @@
namespace PS.IPAM;
using System;
[Serializable]
public class Tag {
public int Id { get; }
public string Type { get; }
public bool ShowTag { get; }
public string BGColor { get; }
public string FGColor { get; }
public bool Compress { get; }
public bool Locked { get; }
public bool UpdateTag { get; }
public Tag(
int id,
string type,
bool showTag,
string BGColor,
string FGColor,
string compress,
string locked,
bool updateTag
) {
this.Id = id;
this.Type = type;
this.ShowTag = showTag;
this.BGColor = BGColor;
this.FGColor = FGColor;
this.Compress = this.StringToBool(compress);
this.Locked = this.StringToBool(locked);
this.UpdateTag = updateTag;
}
public override string ToString() {
return this.Type;
}
private bool StringToBool(string str) {
if (str == "Yes") {
return true;
}
return false;
}
}

41
classlib/class/vlan.cs Normal file
View File

@@ -0,0 +1,41 @@
namespace PS.IPAM;
using System;
using System.Dynamic;
[Serializable]
public class Vlan : DynamicObject {
public int Id { get; }
public int VlanId { get; }
public int DomainId { get; }
public string Name { get; }
public int Number { get; }
public string Description { get; }
public DateTime? EditDate { get; }
public int CustomerId { get; }
public Object? ExtendedData { get; }
public Vlan (
int vlanId,
int domainId,
string name,
int number,
string description,
DateTime? editDate,
int customer_id,
Object? custom_fields
) {
this.Id = vlanId;
this.VlanId = vlanId;
this.DomainId = domainId;
this.Name = name;
this.Number = number;
this.Description = description;
this.EditDate = editDate;
this.CustomerId = customer_id;
this.ExtendedData = custom_fields;
}
public override string ToString()
{
return $"{this.Number}";
}
}

35
classlib/class/vrf.cs Normal file
View File

@@ -0,0 +1,35 @@
namespace PS.IPAM;
using System;
[Serializable]
public class Vrf {
public int Id { get; }
public string Name { get; }
public string RouteDistinguisher { get; }
public string Description { get; }
public string Sections { get; }
public DateTime? EditDate { get; }
public Object? ExtendedData { get; }
public Vrf(
int id,
string name,
string rd,
string description,
string sections,
DateTime? editDate,
Object? custom_fields
) {
this.Id = id;
this.Name = name;
this.RouteDistinguisher = rd;
this.Description = description;
this.Sections = sections;
this.EditDate = editDate;
this.ExtendedData = custom_fields;
}
public override string ToString()
{
return this.Name;
}
}

18
classlib/classlib.csproj Normal file
View 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>

View File

@@ -0,0 +1,8 @@
namespace PS.IPAM;
using System;
[Serializable]
public enum AuthType {
credentials,
token
}

View File

@@ -0,0 +1,14 @@
namespace PS.IPAM;
using System;
[Serializable]
public enum controllers {
user,
vlan,
subnets,
addresses,
sections,
vrf,
l2domains,
tools
}

View File

@@ -0,0 +1,16 @@
namespace PS.IPAM;
using System;
[Serializable]
public enum subcontrollers {
nameservers,
tags,
devices,
device_types,
vlans,
vrfs,
scanagents,
locations,
nat,
racks
}

14
classlib/enum/types.cs Normal file
View File

@@ -0,0 +1,14 @@
namespace PS.IPAM;
using System;
[Serializable]
public enum types {
Address,
Domain,
Section,
Subnetwork,
Nameserver,
Tag,
Vlan,
Vrf
}

View 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
}
}

View File

@@ -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)")
}
}

View 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
}
}

View File

@@ -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"
}
}

View 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"
}
}

View File

@@ -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
}
}

View 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
}
}

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

Binary file not shown.

198
types/types.ps1xml Normal file
View 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>