Refactor IPAM model classes to use records for Address, Subnetwork, Vlan, Vrf, Section, Tag, Domain, Nameserver, and Session; enhance documentation and implement value equality for records.

This commit is contained in:
2026-01-19 17:25:18 +03:00
parent 694822f0d6
commit f56784f2aa
44 changed files with 1601 additions and 1905 deletions

View File

@@ -109,6 +109,13 @@ public class GetAddressCmdletTests : IDisposable
cmdlet.SubnetCIDR.Should().Be("192.168.1.0/24"); cmdlet.SubnetCIDR.Should().Be("192.168.1.0/24");
} }
[Fact]
public void GetAddressCmdlet_InheritsFromBaseCmdlet()
{
var cmdlet = new GetAddressCmdlet();
cmdlet.Should().BeAssignableTo<BaseCmdlet>();
}
// Test the underlying RequestHelper functionality that the cmdlet uses // Test the underlying RequestHelper functionality that the cmdlet uses
[Fact] [Fact]
@@ -129,8 +136,8 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
var result = await RequestHelper.InvokeRequest( var result = await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.addresses, ApiController.Addresses,
types.Address, ModelType.Address,
null, null,
null, null,
new[] { "1" } new[] { "1" }
@@ -155,8 +162,8 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
await RequestHelper.InvokeRequest( await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.addresses, ApiController.Addresses,
types.Address, ModelType.Address,
null, null,
null, null,
new[] { "42" } new[] { "42" }
@@ -177,8 +184,8 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
await RequestHelper.InvokeRequest( await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.addresses, ApiController.Addresses,
types.Address, ModelType.Address,
null, null,
null, null,
new[] { "search", "192.168.1.50" } new[] { "search", "192.168.1.50" }
@@ -199,8 +206,8 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
await RequestHelper.InvokeRequest( await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.addresses, ApiController.Addresses,
types.Address, ModelType.Address,
null, null,
null, null,
new[] { "search_hostname", "myserver.example.com" } new[] { "search_hostname", "myserver.example.com" }
@@ -221,8 +228,8 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
await RequestHelper.InvokeRequest( await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.subnets, ApiController.Subnets,
types.Address, ModelType.Address,
null, null,
null, null,
new[] { "10", "addresses" } new[] { "10", "addresses" }
@@ -243,8 +250,8 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
await RequestHelper.InvokeRequest( await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.addresses, ApiController.Addresses,
types.Address, ModelType.Address,
null, null,
null, null,
new[] { "tags", "2", "addresses" } new[] { "tags", "2", "addresses" }
@@ -269,8 +276,8 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
var result = await RequestHelper.InvokeRequest( var result = await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.subnets, ApiController.Subnets,
types.Address, ModelType.Address,
null, null,
null, null,
new[] { "10", "addresses" } new[] { "10", "addresses" }
@@ -294,8 +301,8 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
var result = await RequestHelper.InvokeRequest( var result = await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.addresses, ApiController.Addresses,
types.Address, ModelType.Address,
null, null,
null, null,
new[] { "999" } new[] { "999" }
@@ -313,11 +320,11 @@ public class GetAddressCmdletTests : IDisposable
// Act // Act
var action = async () => await RequestHelper.InvokeRequest( var action = async () => await RequestHelper.InvokeRequest(
"GET", "GET",
controllers.addresses, ApiController.Addresses,
types.Address ModelType.Address
); );
// Assert // Assert
await action.Should().ThrowAsync<Exception>().WithMessage("No session available!"); await action.Should().ThrowAsync<InvalidOperationException>().WithMessage("No session available!");
} }
} }

View File

@@ -93,11 +93,18 @@ public class NewSessionCmdletTests : IDisposable
session.URL.Should().Be("https://ipam.example.com"); session.URL.Should().Be("https://ipam.example.com");
session.AppID.Should().Be("testapp"); session.AppID.Should().Be("testapp");
session.Token.Should().Be("my-api-token"); session.Token.Should().Be("my-api-token");
session.AuthType.Should().Be(AuthType.token); session.AuthType.Should().Be(AuthType.Token);
session.Expires.Should().BeNull(); session.Expires.Should().BeNull();
session.Credentials.Should().BeNull(); session.Credentials.Should().BeNull();
// Verify it was set as current session // Verify it was set as current session
SessionManager.CurrentSession.Should().BeSameAs(session); SessionManager.CurrentSession.Should().BeSameAs(session);
} }
[Fact]
public void NewSessionCmdlet_InheritsFromBaseCmdlet()
{
var cmdlet = new NewSessionCmdlet();
cmdlet.Should().BeAssignableTo<BaseCmdlet>();
}
} }

View File

@@ -27,9 +27,9 @@ public class RequestHelperTests : IDisposable
_mockHandler?.ForceDispose(); _mockHandler?.ForceDispose();
} }
private void SetupSession(AuthType authType = AuthType.token) private void SetupSession(AuthType authType = AuthType.Token)
{ {
if (authType == AuthType.token) if (authType == AuthType.Token)
{ {
SessionManager.CreateSessionWithToken("https://ipam.example.com", "testapp", "test-token"); SessionManager.CreateSessionWithToken("https://ipam.example.com", "testapp", "test-token");
} }
@@ -37,7 +37,7 @@ public class RequestHelperTests : IDisposable
{ {
// For credentials auth, we need to set up a session manually with future expiry // For credentials auth, we need to set up a session manually with future expiry
var session = new Session( var session = new Session(
AuthType.credentials, AuthType.Credentials,
"cred-token", "cred-token",
"testapp", "testapp",
"https://ipam.example.com", "https://ipam.example.com",
@@ -61,10 +61,10 @@ public class RequestHelperTests : IDisposable
// Arrange - no session set up // Arrange - no session set up
// Act // Act
var action = async () => await RequestHelper.InvokeRequest("GET", controllers.addresses); var action = async () => await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
// Assert // Assert
await action.Should().ThrowAsync<Exception>().WithMessage("No session available!"); await action.Should().ThrowAsync<InvalidOperationException>().WithMessage("No session available!");
} }
[Fact] [Fact]
@@ -76,7 +76,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse("{\"id\":1,\"ip\":\"192.168.1.1\"}"); handler.WithSuccessResponse("{\"id\":1,\"ip\":\"192.168.1.1\"}");
// Act // Act
await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" }); await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address, null, null, new[] { "1" });
// Assert // Assert
handler.LastRequest.Should().NotBeNull(); handler.LastRequest.Should().NotBeNull();
@@ -92,7 +92,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse("[]"); handler.WithSuccessResponse("[]");
// Act // Act
await RequestHelper.InvokeRequest("GET", controllers.subnets, null, subcontrollers.tags, null, new[] { "1" }); await RequestHelper.InvokeRequest("GET", ApiController.Subnets, null, ApiSubController.Tags, null, new[] { "1" });
// Assert // Assert
handler.LastRequest!.RequestUri!.ToString().Should().Contain("/subnets/tags/1/"); handler.LastRequest!.RequestUri!.ToString().Should().Contain("/subnets/tags/1/");
@@ -102,12 +102,12 @@ public class RequestHelperTests : IDisposable
public async Task InvokeRequest_WithTokenAuth_AddsPhpipamTokenHeader() public async Task InvokeRequest_WithTokenAuth_AddsPhpipamTokenHeader()
{ {
// Arrange // Arrange
SetupSession(AuthType.token); SetupSession(AuthType.Token);
var handler = SetupMockHandler(); var handler = SetupMockHandler();
handler.WithSuccessResponse("{}"); handler.WithSuccessResponse("{}");
// Act // Act
await RequestHelper.InvokeRequest("GET", controllers.addresses); await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
// Assert // Assert
handler.GetLastRequestHeader("phpipam-token").Should().Be("test-token"); handler.GetLastRequestHeader("phpipam-token").Should().Be("test-token");
@@ -117,12 +117,12 @@ public class RequestHelperTests : IDisposable
public async Task InvokeRequest_WithCredentialsAuth_AddsTokenHeader() public async Task InvokeRequest_WithCredentialsAuth_AddsTokenHeader()
{ {
// Arrange // Arrange
SetupSession(AuthType.credentials); SetupSession(AuthType.Credentials);
var handler = SetupMockHandler(); var handler = SetupMockHandler();
handler.WithSuccessResponse("{}"); handler.WithSuccessResponse("{}");
// Act // Act
await RequestHelper.InvokeRequest("GET", controllers.addresses); await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
// Assert // Assert
handler.GetLastRequestHeader("token").Should().Be("cred-token"); handler.GetLastRequestHeader("token").Should().Be("cred-token");
@@ -137,7 +137,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse("{}"); handler.WithSuccessResponse("{}");
// Act // Act
await RequestHelper.InvokeRequest("GET", controllers.addresses); await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
// Assert // Assert
handler.LastRequest!.Method.Should().Be(HttpMethod.Get); handler.LastRequest!.Method.Should().Be(HttpMethod.Get);
@@ -152,7 +152,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse("{\"id\":1}"); handler.WithSuccessResponse("{\"id\":1}");
// Act // Act
await RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, new { ip = "10.0.0.1" }); await RequestHelper.InvokeRequest("POST", ApiController.Addresses, null, null, new { ip = "10.0.0.1" });
// Assert // Assert
handler.LastRequest!.Method.Should().Be(HttpMethod.Post); handler.LastRequest!.Method.Should().Be(HttpMethod.Post);
@@ -167,7 +167,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse("{\"id\":1}"); handler.WithSuccessResponse("{\"id\":1}");
// Act // Act
await RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, new { description = "updated" }, new[] { "1" }); await RequestHelper.InvokeRequest("PATCH", ApiController.Addresses, null, null, new { description = "updated" }, new[] { "1" });
// Assert // Assert
handler.LastRequest!.Method.Should().Be(new HttpMethod("PATCH")); handler.LastRequest!.Method.Should().Be(new HttpMethod("PATCH"));
@@ -182,7 +182,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse("{}"); handler.WithSuccessResponse("{}");
// Act // Act
await RequestHelper.InvokeRequest("DELETE", controllers.addresses, null, null, null, new[] { "1" }); await RequestHelper.InvokeRequest("DELETE", ApiController.Addresses, null, null, null, new[] { "1" });
// Assert // Assert
handler.LastRequest!.Method.Should().Be(HttpMethod.Delete); handler.LastRequest!.Method.Should().Be(HttpMethod.Delete);
@@ -197,7 +197,7 @@ public class RequestHelperTests : IDisposable
handler.WithNotFoundResponse(); handler.WithNotFoundResponse();
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "999" }); var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address, null, null, new[] { "999" });
// Assert // Assert
result.Should().BeNull(); result.Should().BeNull();
@@ -212,7 +212,7 @@ public class RequestHelperTests : IDisposable
handler.WithErrorResponse(HttpStatusCode.InternalServerError, "Server error"); handler.WithErrorResponse(HttpStatusCode.InternalServerError, "Server error");
// Act // Act
var action = async () => await RequestHelper.InvokeRequest("GET", controllers.addresses); var action = async () => await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
// Assert // Assert
await action.Should().ThrowAsync<HttpRequestException>(); await action.Should().ThrowAsync<HttpRequestException>();
@@ -249,7 +249,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse(addressJson); handler.WithSuccessResponse(addressJson);
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" }); var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address, null, null, new[] { "1" });
// Assert // Assert
result.Should().BeOfType<Address>(); result.Should().BeOfType<Address>();
@@ -272,7 +272,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse(addressArrayJson); handler.WithSuccessResponse(addressArrayJson);
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.subnets, types.Address, null, null, new[] { "10", "addresses" }); var result = await RequestHelper.InvokeRequest("GET", ApiController.Subnets, ModelType.Address, null, null, new[] { "10", "addresses" });
// Assert // Assert
result.Should().BeAssignableTo<IEnumerable<object>>(); result.Should().BeAssignableTo<IEnumerable<object>>();
@@ -300,7 +300,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse(vlanJson); handler.WithSuccessResponse(vlanJson);
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.vlan, types.Vlan, null, null, new[] { "100" }); var result = await RequestHelper.InvokeRequest("GET", ApiController.Vlan, ModelType.Vlan, null, null, new[] { "100" });
// Assert // Assert
result.Should().BeOfType<Vlan>(); result.Should().BeOfType<Vlan>();
@@ -351,14 +351,14 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse(subnetJson); handler.WithSuccessResponse(subnetJson);
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "1" }); var result = await RequestHelper.InvokeRequest("GET", ApiController.Subnets, ModelType.Subnetwork, null, null, new[] { "1" });
// Assert // Assert
result.Should().BeOfType<Subnetwork>(); result.Should().BeOfType<Subnetwork>();
var subnet = (Subnetwork)result!; var subnet = (Subnetwork)result!;
subnet.Subnet.Should().Be("192.168.1.0"); subnet.Subnet.Should().Be("192.168.1.0");
subnet.Mask.Should().Be(24); subnet.Mask.Should().Be(24);
subnet.GetCIDR().Should().Be("192.168.1.0/24"); subnet.CIDR.Should().Be("192.168.1.0/24");
} }
[Fact] [Fact]
@@ -386,7 +386,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse(sectionJson); handler.WithSuccessResponse(sectionJson);
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { "1" }); var result = await RequestHelper.InvokeRequest("GET", ApiController.Sections, ModelType.Section, null, null, new[] { "1" });
// Assert // Assert
result.Should().BeOfType<Section>(); result.Should().BeOfType<Section>();
@@ -411,12 +411,12 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse(addressJson); handler.WithSuccessResponse(addressJson);
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "1" }); var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address, null, null, new[] { "1" });
// Assert // Assert
var address = (Address)result!; var address = (Address)result!;
address.ExtendedData.Should().NotBeNull(); address.ExtendedData.Should().NotBeNull();
var extendedData = (Dictionary<string, object>)address.ExtendedData!; var extendedData = address.ExtendedData!;
extendedData.Should().ContainKey("custom_environment"); extendedData.Should().ContainKey("custom_environment");
extendedData.Should().ContainKey("custom_owner"); extendedData.Should().ContainKey("custom_owner");
} }
@@ -430,7 +430,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse(@"{""some"": ""data""}"); handler.WithSuccessResponse(@"{""some"": ""data""}");
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.tools); var result = await RequestHelper.InvokeRequest("GET", ApiController.Tools);
// Assert // Assert
result.Should().NotBeNull(); result.Should().NotBeNull();
@@ -447,7 +447,7 @@ public class RequestHelperTests : IDisposable
var parameters = new { ip = "10.0.0.1", subnetId = 5, description = "New address" }; var parameters = new { ip = "10.0.0.1", subnetId = 5, description = "New address" };
// Act // Act
await RequestHelper.InvokeRequest("POST", controllers.addresses, null, null, parameters); await RequestHelper.InvokeRequest("POST", ApiController.Addresses, null, null, parameters);
// Assert // Assert
handler.LastRequest!.Content.Should().NotBeNull(); handler.LastRequest!.Content.Should().NotBeNull();
@@ -465,7 +465,7 @@ public class RequestHelperTests : IDisposable
handler.WithSuccessResponse("{}"); handler.WithSuccessResponse("{}");
// Act // Act
await RequestHelper.InvokeRequest("GET", controllers.addresses); await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
// Assert // Assert
handler.LastRequest!.Headers.Accept.Should().Contain(h => h.MediaType == "application/json"); handler.LastRequest!.Headers.Accept.Should().Contain(h => h.MediaType == "application/json");
@@ -480,7 +480,7 @@ public class RequestHelperTests : IDisposable
handler.WithResponse(HttpStatusCode.OK, "", "application/json"); handler.WithResponse(HttpStatusCode.OK, "", "application/json");
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses); var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses);
// Assert // Assert
result.Should().BeNull(); result.Should().BeNull();
@@ -495,7 +495,7 @@ public class RequestHelperTests : IDisposable
handler.WithJsonResponse(@"{""code"": 200, ""success"": true, ""data"": null}"); handler.WithJsonResponse(@"{""code"": 200, ""success"": true, ""data"": null}");
// Act // Act
var result = await RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address); var result = await RequestHelper.InvokeRequest("GET", ApiController.Addresses, ModelType.Address);
// Assert // Assert
result.Should().BeNull(); result.Should().BeNull();

View File

@@ -21,60 +21,60 @@ public class SessionManagerTests : IDisposable
} }
[Fact] [Fact]
public void TestSession_WhenNoSession_ReturnsNoToken() public void GetSessionStatus_WhenNoSession_ReturnsNoSession()
{ {
// Arrange // Arrange
SessionManager.CurrentSession = null; SessionManager.CurrentSession = null;
// Act // Act
var result = SessionManager.TestSession(); var result = SessionManager.GetSessionStatus();
// Assert // Assert
result.Should().Be("NoToken"); result.Should().Be(SessionStatus.NoSession);
} }
[Fact] [Fact]
public void TestSession_WhenSessionWithNullExpires_ReturnsValid() public void GetSessionStatus_WhenSessionWithNullExpires_ReturnsValid()
{ {
// Arrange // Arrange
var session = new Session(AuthType.token, "test-token", "app", "https://test.com", null, null); var session = new Session(AuthType.Token, "test-token", "app", "https://test.com", null, null);
SessionManager.CurrentSession = session; SessionManager.CurrentSession = session;
// Act // Act
var result = SessionManager.TestSession(); var result = SessionManager.GetSessionStatus();
// Assert // Assert
result.Should().Be("Valid"); result.Should().Be(SessionStatus.Valid);
} }
[Fact] [Fact]
public void TestSession_WhenSessionNotExpired_ReturnsValid() public void GetSessionStatus_WhenSessionNotExpired_ReturnsValid()
{ {
// Arrange // Arrange
var futureExpiry = DateTime.Now.AddHours(1); var futureExpiry = DateTime.Now.AddHours(1);
var session = new Session(AuthType.credentials, "test-token", "app", "https://test.com", futureExpiry, null); var session = new Session(AuthType.Credentials, "test-token", "app", "https://test.com", futureExpiry, null);
SessionManager.CurrentSession = session; SessionManager.CurrentSession = session;
// Act // Act
var result = SessionManager.TestSession(); var result = SessionManager.GetSessionStatus();
// Assert // Assert
result.Should().Be("Valid"); result.Should().Be(SessionStatus.Valid);
} }
[Fact] [Fact]
public void TestSession_WhenSessionExpired_ReturnsExpired() public void GetSessionStatus_WhenSessionExpired_ReturnsExpired()
{ {
// Arrange // Arrange
var pastExpiry = DateTime.Now.AddHours(-1); var pastExpiry = DateTime.Now.AddHours(-1);
var session = new Session(AuthType.credentials, "test-token", "app", "https://test.com", pastExpiry, null); var session = new Session(AuthType.Credentials, "test-token", "app", "https://test.com", pastExpiry, null);
SessionManager.CurrentSession = session; SessionManager.CurrentSession = session;
// Act // Act
var result = SessionManager.TestSession(); var result = SessionManager.GetSessionStatus();
// Assert // Assert
result.Should().Be("Expired"); result.Should().Be(SessionStatus.Expired);
} }
[Fact] [Fact]
@@ -93,7 +93,7 @@ public class SessionManagerTests : IDisposable
session.URL.Should().Be(url); session.URL.Should().Be(url);
session.AppID.Should().Be(appId); session.AppID.Should().Be(appId);
session.Token.Should().Be(token); session.Token.Should().Be(token);
session.AuthType.Should().Be(AuthType.token); session.AuthType.Should().Be(AuthType.Token);
session.Expires.Should().BeNull(); session.Expires.Should().BeNull();
session.Credentials.Should().BeNull(); session.Credentials.Should().BeNull();
} }
@@ -144,7 +144,7 @@ public class SessionManagerTests : IDisposable
public void CurrentSession_CanBeSetDirectly() public void CurrentSession_CanBeSetDirectly()
{ {
// Arrange // Arrange
var session = new Session(AuthType.token, "token", "app", "https://test.com", null, null); var session = new Session(AuthType.Token, "token", "app", "https://test.com", null, null);
// Act // Act
SessionManager.CurrentSession = session; SessionManager.CurrentSession = session;

View File

@@ -55,7 +55,7 @@ public class AddressTests
address.Note.Should().Be(note); address.Note.Should().Be(note);
address.LastSeen.Should().Be(lastSeen); address.LastSeen.Should().Be(lastSeen);
address.ExcludePing.Should().Be(excludePing); address.ExcludePing.Should().Be(excludePing);
address.PTRignore.Should().Be(ptrIgnore); address.PTRIgnore.Should().Be(ptrIgnore);
address.PTR.Should().Be(ptr); address.PTR.Should().Be(ptr);
address.FirewallAddressObject.Should().Be(firewallObject); address.FirewallAddressObject.Should().Be(firewallObject);
address.EditDate.Should().Be(editDate); address.EditDate.Should().Be(editDate);
@@ -113,4 +113,24 @@ public class AddressTests
// Act & Assert // Act & Assert
address.ToString().Should().Be(expectedIp); address.ToString().Should().Be(expectedIp);
} }
[Fact]
public void Record_Equality_WorksCorrectly()
{
// Arrange
var address1 = new Address(
1, 10, "192.168.1.1", false, "Test", "host", "", "",
0, 0, "", "", "", null, false,
false, 0, "", null, 0, null
);
var address2 = new Address(
1, 10, "192.168.1.1", false, "Test", "host", "", "",
0, 0, "", "", "", null, false,
false, 0, "", null, 0, null
);
// Assert
address1.Should().Be(address2);
}
} }

View File

@@ -57,7 +57,7 @@ public class NameserverTests
} }
[Fact] [Fact]
public void Constructor_WithEmptyNameservers_ReturnsArrayWithEmptyString() public void Constructor_WithEmptyNameservers_ReturnsEmptyArray()
{ {
// Arrange // Arrange
var nameServersString = ""; var nameServersString = "";
@@ -65,9 +65,8 @@ public class NameserverTests
// Act // Act
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null); var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
// Assert // Assert - Empty entries are excluded
nameserver.NameServers.Should().HaveCount(1); nameserver.NameServers.Should().BeEmpty();
nameserver.NameServers[0].Should().BeEmpty();
} }
[Fact] [Fact]
@@ -79,4 +78,27 @@ public class NameserverTests
// Assert // Assert
nameserver.EditDate.Should().BeNull(); nameserver.EditDate.Should().BeNull();
} }
[Fact]
public void Constructor_WithSemicolonOnlyString_ReturnsEmptyArray()
{
// Arrange - edge case with just semicolons
var nameServersString = ";;;";
// Act
var nameserver = new Nameserver(1, "Test", nameServersString, "", "", null);
// Assert
nameserver.NameServers.Should().BeEmpty();
}
[Fact]
public void ToString_ReturnsName()
{
// Arrange
var nameserver = new Nameserver(1, "Google DNS", "8.8.8.8", "", "", null);
// Act & Assert
nameserver.ToString().Should().Be("Google DNS");
}
} }

View File

@@ -10,7 +10,7 @@ public class SessionTests
public void Constructor_WithCredentialsAuth_SetsAllProperties() public void Constructor_WithCredentialsAuth_SetsAllProperties()
{ {
// Arrange // Arrange
var authType = AuthType.credentials; var authType = AuthType.Credentials;
var token = "test-token-123"; var token = "test-token-123";
var appId = "myApp"; var appId = "myApp";
var url = "https://ipam.example.com"; var url = "https://ipam.example.com";
@@ -21,7 +21,7 @@ public class SessionTests
var session = new Session(authType, token, appId, url, expires, credentials); var session = new Session(authType, token, appId, url, expires, credentials);
// Assert // Assert
session.AuthType.Should().Be(AuthType.credentials); session.AuthType.Should().Be(AuthType.Credentials);
session.Token.Should().Be(token); session.Token.Should().Be(token);
session.AppID.Should().Be(appId); session.AppID.Should().Be(appId);
session.URL.Should().Be(url); session.URL.Should().Be(url);
@@ -33,7 +33,7 @@ public class SessionTests
public void Constructor_WithTokenAuth_SetsAllProperties() public void Constructor_WithTokenAuth_SetsAllProperties()
{ {
// Arrange // Arrange
var authType = AuthType.token; var authType = AuthType.Token;
var token = "static-api-token"; var token = "static-api-token";
var appId = "apiApp"; var appId = "apiApp";
var url = "https://ipam.test.com"; var url = "https://ipam.test.com";
@@ -42,7 +42,7 @@ public class SessionTests
var session = new Session(authType, token, appId, url, null, null); var session = new Session(authType, token, appId, url, null, null);
// Assert // Assert
session.AuthType.Should().Be(AuthType.token); session.AuthType.Should().Be(AuthType.Token);
session.Token.Should().Be(token); session.Token.Should().Be(token);
session.AppID.Should().Be(appId); session.AppID.Should().Be(appId);
session.URL.Should().Be(url); session.URL.Should().Be(url);
@@ -54,7 +54,7 @@ public class SessionTests
public void Token_CanBeModified() public void Token_CanBeModified()
{ {
// Arrange // Arrange
var session = new Session(AuthType.credentials, "old-token", "app", "https://test.com", null, null); var session = new Session(AuthType.Credentials, "old-token", "app", "https://test.com", null, null);
// Act // Act
session.Token = "new-token"; session.Token = "new-token";
@@ -67,7 +67,7 @@ public class SessionTests
public void Expires_CanBeModified() public void Expires_CanBeModified()
{ {
// Arrange // Arrange
var session = new Session(AuthType.credentials, "token", "app", "https://test.com", null, null); var session = new Session(AuthType.Credentials, "token", "app", "https://test.com", null, null);
var newExpiry = new DateTime(2027, 1, 1); var newExpiry = new DateTime(2027, 1, 1);
// Act // Act
@@ -78,15 +78,13 @@ public class SessionTests
} }
[Fact] [Fact]
public void ToString_ReturnsDefaultObjectString() public void Record_Equality_WorksForSameValues()
{ {
// Arrange // Arrange
var session = new Session(AuthType.token, "token", "app", "https://test.com", null, null); var session1 = new Session(AuthType.Token, "token", "app", "https://test.com", null, null);
var session2 = new Session(AuthType.Token, "token", "app", "https://test.com", null, null);
// Act // Assert - Records use value equality
var result = session.ToString(); session1.Should().Be(session2);
// Assert
result.Should().Contain("PS.IPAM.Session");
} }
} }

View File

@@ -93,13 +93,13 @@ public class SubnetworkTests
[InlineData("10.0.0.0", 8, "10.0.0.0/8")] [InlineData("10.0.0.0", 8, "10.0.0.0/8")]
[InlineData("172.16.0.0", 16, "172.16.0.0/16")] [InlineData("172.16.0.0", 16, "172.16.0.0/16")]
[InlineData("192.168.100.0", 30, "192.168.100.0/30")] [InlineData("192.168.100.0", 30, "192.168.100.0/30")]
public void GetCIDR_ReturnsCidrNotation(string subnet, int mask, string expectedCidr) public void CIDR_ReturnsCidrNotation(string subnet, int mask, string expectedCidr)
{ {
// Arrange // Arrange
var subnetwork = CreateSubnetwork(subnet, mask); var subnetwork = CreateSubnetwork(subnet, mask);
// Act // Act
var result = subnetwork.GetCIDR(); var result = subnetwork.CIDR;
// Assert // Assert
result.Should().Be(expectedCidr); result.Should().Be(expectedCidr);
@@ -119,16 +119,31 @@ public class SubnetworkTests
} }
[Fact] [Fact]
public void ToString_EqualsGetCIDR() public void ToString_EqualsCIDRProperty()
{ {
// Arrange // Arrange
var subnetwork = CreateSubnetwork("172.20.0.0", 12); var subnetwork = CreateSubnetwork("172.20.0.0", 12);
// Act & Assert // Act & Assert
subnetwork.ToString().Should().Be(subnetwork.GetCIDR()); subnetwork.ToString().Should().Be(subnetwork.CIDR);
} }
private static Subnetwork CreateSubnetwork(string subnet, int mask) [Fact]
public void Record_Equality_WorksCorrectly()
{
// Arrange - use same calculation object for equality comparison
var calculation = new { maxhosts = 254 };
var subnet1 = CreateSubnetwork("192.168.1.0", 24, calculation);
var subnet2 = CreateSubnetwork("192.168.1.0", 24, calculation);
// Assert - records use value equality (except for the Calculation object reference)
subnet1.Id.Should().Be(subnet2.Id);
subnet1.Subnet.Should().Be(subnet2.Subnet);
subnet1.Mask.Should().Be(subnet2.Mask);
subnet1.CIDR.Should().Be(subnet2.CIDR);
}
private static Subnetwork CreateSubnetwork(string subnet, int mask, object? calculation = null)
{ {
return new Subnetwork( return new Subnetwork(
1, subnet, mask, 1, "", "", "", 1, subnet, mask, 1, "", "", "",
@@ -136,7 +151,7 @@ public class SubnetworkTests
"", false, false, false, false, "", false, false, false, false,
false, 0, false, false, false, false, false, 0, false, false, false, false,
0, 0, 0, null, null, null, 0, 0, 0, null, null, null,
new object(), null calculation ?? new object(), null
); );
} }
} }

View File

@@ -26,28 +26,13 @@ public class TagTests
tag.Id.Should().Be(id); tag.Id.Should().Be(id);
tag.Type.Should().Be(type); tag.Type.Should().Be(type);
tag.ShowTag.Should().Be(showTag); tag.ShowTag.Should().Be(showTag);
tag.BGColor.Should().Be(bgColor); tag.BackgroundColor.Should().Be(bgColor);
tag.FGColor.Should().Be(fgColor); tag.ForegroundColor.Should().Be(fgColor);
tag.Compress.Should().BeTrue(); tag.Compress.Should().Be(compress);
tag.Locked.Should().BeFalse(); tag.Locked.Should().Be(locked);
tag.UpdateTag.Should().Be(updateTag); 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] [Theory]
[InlineData("Used")] [InlineData("Used")]
[InlineData("Available")] [InlineData("Available")]
@@ -66,12 +51,13 @@ public class TagTests
} }
[Fact] [Fact]
public void Locked_WithYes_IsTrue() public void Record_Equality_WorksCorrectly()
{ {
// Arrange & Act // Arrange
var tag = new Tag(1, "Test", false, "", "", "No", "Yes", false); var tag1 = new Tag(1, "Used", true, "#fff", "#000", "Yes", "No", false);
var tag2 = new Tag(1, "Used", true, "#fff", "#000", "Yes", "No", false);
// Assert // Assert
tag.Locked.Should().BeTrue(); tag1.Should().Be(tag2);
} }
} }

View File

@@ -1,24 +1,30 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
[Cmdlet("Assign", "Tag")] /// <summary>
public class AssignTagCmdlet : PSCmdlet /// Assigns a tag to an address in phpIPAM.
/// </summary>
[Cmdlet("Assign", "Tag", SupportsShouldProcess = true)]
[OutputType(typeof(Address))]
public class AssignTagCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0)] Position = 0,
HelpMessage = "The address to assign the tag to.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Address? AddressObject { get; set; } public Address? AddressObject { get; set; }
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
Position = 1)] Position = 1,
HelpMessage = "The tag to assign.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Tag? Tag { get; set; } public Tag? Tag { get; set; }
@@ -26,14 +32,25 @@ public class AssignTagCmdlet : PSCmdlet
{ {
try try
{ {
var identifiers = new List<string> { AddressObject!.Id.ToString() }; var identifiers = new[] { AddressObject!.Id.ToString() };
var body = new Dictionary<string, object> var body = new Dictionary<string, object>
{ {
{ "tag", Tag!.Id } ["tag"] = Tag!.Id
}; };
RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, body, identifiers.ToArray()) if (ShouldProcess($"Address {AddressObject.Ip}", $"Assign tag '{Tag.Type}'"))
.GetAwaiter().GetResult(); {
RequestHelper.InvokeRequest(
"PATCH", ApiController.Addresses, null, null, body, identifiers
).GetAwaiter().GetResult();
// Return the updated address
var address = RequestHelper.InvokeRequest(
"GET", ApiController.Addresses, ModelType.Address, null, null, identifiers
).GetAwaiter().GetResult();
WriteResult(address);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,21 +1,17 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Closes the current phpIPAM API session.
/// </summary>
[Cmdlet(VerbsCommon.Close, "Session")] [Cmdlet(VerbsCommon.Close, "Session")]
public class CloseSessionCmdlet : PSCmdlet public class CloseSessionCmdlet : BaseCmdlet
{ {
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try SessionManager.CloseSession();
{ WriteVerbose("Session closed successfully.");
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

@@ -1,21 +1,25 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using System.Net; using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves IP address entries from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Address", DefaultParameterSetName = "ByID")] [Cmdlet(VerbsCommon.Get, "Address", DefaultParameterSetName = "ByID")]
[OutputType(typeof(Address))] [OutputType(typeof(Address))]
public class GetAddressCmdlet : PSCmdlet public class GetAddressCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The address ID to retrieve.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int Id { get; set; } public int Id { get; set; }
@@ -24,7 +28,8 @@ public class GetAddressCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByIP")] ParameterSetName = "ByIP",
HelpMessage = "The IP address to search for.")]
[Parameter( [Parameter(
Mandatory = false, Mandatory = false,
ValueFromPipeline = true, ValueFromPipeline = true,
@@ -39,7 +44,8 @@ public class GetAddressCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByHostName")] ParameterSetName = "ByHostName",
HelpMessage = "The hostname to search for.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? HostName { get; set; } public string? HostName { get; set; }
@@ -48,7 +54,8 @@ public class GetAddressCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByHostBase")] ParameterSetName = "ByHostBase",
HelpMessage = "The hostname base pattern to search for.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? HostBase { get; set; } public string? HostBase { get; set; }
@@ -57,7 +64,8 @@ public class GetAddressCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByTag")] ParameterSetName = "ByTag",
HelpMessage = "The tag ID to filter addresses by.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? TagId { get; set; } public int? TagId { get; set; }
@@ -66,7 +74,8 @@ public class GetAddressCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetId")] ParameterSetName = "BySubnetId",
HelpMessage = "The subnet ID to get addresses from.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? SubnetId { get; set; } public int? SubnetId { get; set; }
@@ -75,7 +84,8 @@ public class GetAddressCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetCIDR")] ParameterSetName = "BySubnetCIDR",
HelpMessage = "The subnet in CIDR notation to get addresses from.")]
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")] [ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? SubnetCIDR { get; set; } public string? SubnetCIDR { get; set; }
@@ -84,7 +94,7 @@ public class GetAddressCmdlet : PSCmdlet
{ {
try try
{ {
var controller = controllers.addresses; var controller = ApiController.Addresses;
var identifiers = new List<string>(); var identifiers = new List<string>();
switch (ParameterSetName) switch (ParameterSetName)
@@ -92,23 +102,28 @@ public class GetAddressCmdlet : PSCmdlet
case "ByID": case "ByID":
identifiers.Add(Id.ToString()); identifiers.Add(Id.ToString());
break; break;
case "ByIP": case "ByIP":
identifiers.Add("search"); identifiers.Add("search");
identifiers.Add(IP!.ToString()); identifiers.Add(IP!.ToString());
break; break;
case "ByHostName": case "ByHostName":
identifiers.Add("search_hostname"); identifiers.Add("search_hostname");
identifiers.Add(HostName!); identifiers.Add(HostName!);
break; break;
case "ByHostBase": case "ByHostBase":
identifiers.Add("search_hostbase"); identifiers.Add("search_hostbase");
identifiers.Add(HostBase!); identifiers.Add(HostBase!);
break; break;
case "ByTag": case "ByTag":
identifiers.Add("tags"); identifiers.Add("tags");
identifiers.Add(TagId!.Value.ToString()); identifiers.Add(TagId!.Value.ToString());
identifiers.Add("addresses"); identifiers.Add("addresses");
break; break;
case "BySubnetId": case "BySubnetId":
if (IP != null) if (IP != null)
{ {
@@ -117,42 +132,34 @@ public class GetAddressCmdlet : PSCmdlet
} }
else else
{ {
controller = controllers.subnets; controller = ApiController.Subnets;
identifiers.Add(SubnetId!.Value.ToString()); identifiers.Add(SubnetId!.Value.ToString());
identifiers.Add("addresses"); identifiers.Add("addresses");
} }
break; break;
case "BySubnetCIDR": case "BySubnetCIDR":
controller = controllers.subnets; controller = ApiController.Subnets;
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", SubnetCIDR! }) var subnet = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
new[] { "cidr", SubnetCIDR! }
).GetAwaiter().GetResult() as Subnetwork;
if (subnet == null) if (subnet == null)
{ {
throw new Exception("Cannot find subnet!"); throw new ItemNotFoundException($"Subnet '{SubnetCIDR}' not found.");
} }
var subnetObj = subnet as Subnetwork;
identifiers.Add(subnetObj!.Id.ToString()); identifiers.Add(subnet.Id.ToString());
identifiers.Add("addresses"); identifiers.Add("addresses");
break; break;
} }
var result = RequestHelper.InvokeRequest("GET", controller, types.Address, null, null, identifiers.ToArray()) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", controller, ModelType.Address, null, null, identifiers.ToArray()
).GetAwaiter().GetResult();
if (result != null) WriteResult(result);
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,20 +1,23 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Gets the first available IP address in a subnet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "FirstFreeIP", DefaultParameterSetName = "ByID")] [Cmdlet(VerbsCommon.Get, "FirstFreeIP", DefaultParameterSetName = "ByID")]
public class GetFirstFreeIPCmdlet : PSCmdlet public class GetFirstFreeIPCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByCIDR")] ParameterSetName = "ByCIDR",
HelpMessage = "The subnet in CIDR notation.")]
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")] [ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? CIDR { get; set; } public string? CIDR { get; set; }
@@ -24,7 +27,8 @@ public class GetFirstFreeIPCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The subnet ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -33,7 +37,8 @@ public class GetFirstFreeIPCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetObject")] ParameterSetName = "BySubnetObject",
HelpMessage = "The subnet object.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Subnetwork? SubnetObject { get; set; } public Subnetwork? SubnetObject { get; set; }
@@ -41,30 +46,12 @@ public class GetFirstFreeIPCmdlet : PSCmdlet
{ {
try try
{ {
int subnetId; var subnetId = GetSubnetId();
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 identifiers = new List<string> { subnetId.ToString(), "first_free" };
var result = RequestHelper.InvokeRequest("GET", controllers.subnets, null, null, null, identifiers.ToArray())
.GetAwaiter().GetResult(); var result = RequestHelper.InvokeRequest(
"GET", ApiController.Subnets, null, null, null, identifiers.ToArray()
).GetAwaiter().GetResult();
if (result != null) if (result != null)
{ {
@@ -76,4 +63,28 @@ public class GetFirstFreeIPCmdlet : PSCmdlet
WriteError(new ErrorRecord(ex, "GetFirstFreeIPError", ErrorCategory.InvalidOperation, null)); WriteError(new ErrorRecord(ex, "GetFirstFreeIPError", ErrorCategory.InvalidOperation, null));
} }
} }
private int GetSubnetId()
{
switch (ParameterSetName)
{
case "ByCIDR":
var subnet = RequestHelper.InvokeRequest(
"GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
new[] { "cidr", CIDR! }
).GetAwaiter().GetResult() as Subnetwork;
if (subnet == null)
{
throw new ItemNotFoundException($"Subnet '{CIDR}' not found.");
}
return subnet.Id;
case "BySubnetObject":
return SubnetObject!.Id;
default:
return Id!.Value;
}
}
} }

View File

@@ -1,20 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves L2 domain information from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "L2Domain", DefaultParameterSetName = "ByID")] [Cmdlet(VerbsCommon.Get, "L2Domain", DefaultParameterSetName = "ByID")]
[OutputType(typeof(Domain))] [OutputType(typeof(Domain))]
public class GetL2DomainCmdlet : PSCmdlet public class GetL2DomainCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = false, Mandatory = false,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The L2 domain ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -23,28 +27,18 @@ public class GetL2DomainCmdlet : PSCmdlet
try try
{ {
var identifiers = new List<string>(); var identifiers = new List<string>();
if (Id.HasValue) if (Id.HasValue)
{ {
identifiers.Add(Id.Value.ToString()); identifiers.Add(Id.Value.ToString());
} }
var result = RequestHelper.InvokeRequest("GET", controllers.l2domains, types.Domain, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.L2Domains, ModelType.Domain, null, null,
identifiers.Count > 0 ? identifiers.ToArray() : null
).GetAwaiter().GetResult();
if (result != null) WriteResult(result);
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,20 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves nameserver information from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Nameserver", DefaultParameterSetName = "NoParams")] [Cmdlet(VerbsCommon.Get, "Nameserver", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Nameserver))] [OutputType(typeof(Nameserver))]
public class GetNameserverCmdlet : PSCmdlet public class GetNameserverCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The nameserver ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -23,28 +27,18 @@ public class GetNameserverCmdlet : PSCmdlet
try try
{ {
var identifiers = new List<string>(); var identifiers = new List<string>();
if (Id.HasValue) if (Id.HasValue)
{ {
identifiers.Add(Id.Value.ToString()); identifiers.Add(Id.Value.ToString());
} }
var result = RequestHelper.InvokeRequest("GET", controllers.tools, types.Nameserver, subcontrollers.nameservers, null, identifiers.Count > 0 ? identifiers.ToArray() : null) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.Tools, ModelType.Nameserver, ApiSubController.Nameservers,
null, identifiers.Count > 0 ? identifiers.ToArray() : null
).GetAwaiter().GetResult();
if (result != null) WriteResult(result);
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,20 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using System.Net; using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves permission information from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Permissions")] [Cmdlet(VerbsCommon.Get, "Permissions")]
public class GetPermissionsCmdlet : PSCmdlet public class GetPermissionsCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The address ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? Id { get; set; } public string? Id { get; set; }
@@ -23,7 +27,8 @@ public class GetPermissionsCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByIP")] ParameterSetName = "ByIP",
HelpMessage = "The IP address to search for.")]
[Parameter( [Parameter(
Mandatory = false, Mandatory = false,
ValueFromPipeline = true, ValueFromPipeline = true,
@@ -38,7 +43,8 @@ public class GetPermissionsCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByHostName")] ParameterSetName = "ByHostName",
HelpMessage = "The hostname to search for.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? HostName { get; set; } public string? HostName { get; set; }
@@ -47,7 +53,8 @@ public class GetPermissionsCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByTag")] ParameterSetName = "ByTag",
HelpMessage = "The tag ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? TagId { get; set; } public string? TagId { get; set; }
@@ -56,7 +63,8 @@ public class GetPermissionsCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetId")] ParameterSetName = "BySubnetId",
HelpMessage = "The subnet ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? SubnetId { get; set; } public string? SubnetId { get; set; }
@@ -65,7 +73,8 @@ public class GetPermissionsCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetCIDR")] ParameterSetName = "BySubnetCIDR",
HelpMessage = "The subnet in CIDR notation.")]
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")] [ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? SubnetCIDR { get; set; } public string? SubnetCIDR { get; set; }
@@ -74,7 +83,7 @@ public class GetPermissionsCmdlet : PSCmdlet
{ {
try try
{ {
var controller = controllers.addresses; var controller = ApiController.Addresses;
var identifiers = new List<string>(); var identifiers = new List<string>();
switch (ParameterSetName) switch (ParameterSetName)
@@ -82,19 +91,23 @@ public class GetPermissionsCmdlet : PSCmdlet
case "ByID": case "ByID":
identifiers.Add(Id!); identifiers.Add(Id!);
break; break;
case "ByIP": case "ByIP":
identifiers.Add("search"); identifiers.Add("search");
identifiers.Add(IP!.ToString()); identifiers.Add(IP!.ToString());
break; break;
case "ByHostName": case "ByHostName":
identifiers.Add("search_hostname"); identifiers.Add("search_hostname");
identifiers.Add(HostName!); identifiers.Add(HostName!);
break; break;
case "ByTag": case "ByTag":
identifiers.Add("tags"); identifiers.Add("tags");
identifiers.Add(TagId!); identifiers.Add(TagId!);
identifiers.Add("addresses"); identifiers.Add("addresses");
break; break;
case "BySubnetId": case "BySubnetId":
if (IP != null) if (IP != null)
{ {
@@ -103,42 +116,34 @@ public class GetPermissionsCmdlet : PSCmdlet
} }
else else
{ {
controller = controllers.subnets; controller = ApiController.Subnets;
identifiers.Add(SubnetId!); identifiers.Add(SubnetId!);
identifiers.Add("addresses"); identifiers.Add("addresses");
} }
break; break;
case "BySubnetCIDR": case "BySubnetCIDR":
controller = controllers.subnets; controller = ApiController.Subnets;
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", SubnetCIDR! }) var subnet = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
new[] { "cidr", SubnetCIDR! }
).GetAwaiter().GetResult() as Subnetwork;
if (subnet == null) if (subnet == null)
{ {
throw new Exception("Cannot find subnet!"); throw new ItemNotFoundException($"Subnet '{SubnetCIDR}' not found.");
} }
var subnetObj = subnet as Subnetwork;
identifiers.Add(subnetObj!.Id.ToString()); identifiers.Add(subnet.Id.ToString());
identifiers.Add("addresses"); identifiers.Add("addresses");
break; break;
} }
var result = RequestHelper.InvokeRequest("GET", controller, null, null, null, identifiers.ToArray()) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", controller, null, null, null, identifiers.ToArray()
).GetAwaiter().GetResult();
if (result != null) WriteResult(result);
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,19 +1,23 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves section information from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Section", DefaultParameterSetName = "NoParams")] [Cmdlet(VerbsCommon.Get, "Section", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Section))] [OutputType(typeof(Section))]
public class GetSectionCmdlet : PSCmdlet public class GetSectionCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = false, Mandatory = false,
ValueFromPipeline = true, ValueFromPipeline = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The section ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -21,7 +25,8 @@ public class GetSectionCmdlet : PSCmdlet
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
Position = 0, Position = 0,
ParameterSetName = "ByName")] ParameterSetName = "ByName",
HelpMessage = "The section name.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? Name { get; set; } public string? Name { get; set; }
@@ -30,6 +35,7 @@ public class GetSectionCmdlet : PSCmdlet
try try
{ {
var identifiers = new List<string>(); var identifiers = new List<string>();
if (ParameterSetName == "ByID" && Id.HasValue) if (ParameterSetName == "ByID" && Id.HasValue)
{ {
identifiers.Add(Id.Value.ToString()); identifiers.Add(Id.Value.ToString());
@@ -39,23 +45,12 @@ public class GetSectionCmdlet : PSCmdlet
identifiers.Add(Name!); identifiers.Add(Name!);
} }
var result = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.Sections, ModelType.Section, null, null,
identifiers.Count > 0 ? identifiers.ToArray() : null
).GetAwaiter().GetResult();
if (result != null) WriteResult(result);
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,22 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Management.Automation; using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves subnet information from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Subnet", DefaultParameterSetName = "NoParams")] [Cmdlet(VerbsCommon.Get, "Subnet", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Subnetwork))] [OutputType(typeof(Subnetwork))]
public class GetSubnetCmdlet : PSCmdlet public class GetSubnetCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByCIDR")] ParameterSetName = "ByCIDR",
HelpMessage = "The subnet in CIDR notation (e.g., 192.168.1.0/24).")]
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")] [ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? CIDR { get; set; } public string? CIDR { get; set; }
@@ -26,7 +28,8 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The subnet ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -35,7 +38,8 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySectionId")] ParameterSetName = "BySectionId",
HelpMessage = "The section ID to get subnets from.")]
[Parameter( [Parameter(
Mandatory = false, Mandatory = false,
ValueFromPipeline = true, ValueFromPipeline = true,
@@ -56,7 +60,8 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySectionName")] ParameterSetName = "BySectionName",
HelpMessage = "The section name to get subnets from.")]
[Parameter( [Parameter(
Mandatory = false, Mandatory = false,
ValueFromPipeline = true, ValueFromPipeline = true,
@@ -77,7 +82,8 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByVrfId")] ParameterSetName = "ByVrfId",
HelpMessage = "The VRF ID to get subnets from.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? VrfId { get; set; } public int? VrfId { get; set; }
@@ -86,7 +92,8 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByVlanId")] ParameterSetName = "ByVlanId",
HelpMessage = "The VLAN ID to get subnets from.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? VlanId { get; set; } public int? VlanId { get; set; }
@@ -95,7 +102,8 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByVlanNumber")] ParameterSetName = "ByVlanNumber",
HelpMessage = "The VLAN number to get subnets from.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? VlanNumber { get; set; } public int? VlanNumber { get; set; }
@@ -104,7 +112,8 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 1, Position = 1,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "Get child subnets (slaves).")]
public SwitchParameter Slaves { get; set; } public SwitchParameter Slaves { get; set; }
[Parameter( [Parameter(
@@ -112,7 +121,8 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 2, Position = 2,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "Get child subnets recursively.")]
public SwitchParameter Recurse { get; set; } public SwitchParameter Recurse { get; set; }
[Parameter( [Parameter(
@@ -120,16 +130,16 @@ public class GetSubnetCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 1, Position = 1,
ParameterSetName = "ByVlanNumber")] ParameterSetName = "ByVlanNumber",
HelpMessage = "The L2 domain ID to narrow VLAN search.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? VlanDomainId { get; set; } public int? VlanDomainId { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try try
{ {
var controller = controllers.subnets; var controller = ApiController.Subnets;
var identifiers = new List<string>(); var identifiers = new List<string>();
switch (ParameterSetName) switch (ParameterSetName)
@@ -138,6 +148,7 @@ public class GetSubnetCmdlet : PSCmdlet
identifiers.Add("cidr"); identifiers.Add("cidr");
identifiers.Add(CIDR!); identifiers.Add(CIDR!);
break; break;
case "ByID": case "ByID":
identifiers.Add(Id!.Value.ToString()); identifiers.Add(Id!.Value.ToString());
if (Slaves.IsPresent) if (Slaves.IsPresent)
@@ -145,117 +156,122 @@ public class GetSubnetCmdlet : PSCmdlet
identifiers.Add(Recurse.IsPresent ? "slaves_recursive" : "slaves"); identifiers.Add(Recurse.IsPresent ? "slaves_recursive" : "slaves");
} }
break; break;
case "BySectionId": case "BySectionId":
controller = controllers.sections; controller = ApiController.Sections;
identifiers.Add(SectionId!.Value.ToString()); identifiers.Add(SectionId!.Value.ToString());
identifiers.Add("subnets"); identifiers.Add("subnets");
break; break;
case "BySectionName": case "BySectionName":
controller = controllers.sections; controller = ApiController.Sections;
var section = RequestHelper.InvokeRequest("GET", controllers.sections, types.Section, null, null, new[] { SectionName! }) var section = GetSectionByName(SectionName!);
.GetAwaiter().GetResult(); identifiers.Add(section.Id.ToString());
if (section == null)
{
throw new Exception("Cannot find section!");
}
var sectionObj = section as Section;
identifiers.Add(sectionObj!.Id.ToString());
identifiers.Add("subnets"); identifiers.Add("subnets");
break; break;
case "ByVrfId": case "ByVrfId":
controller = controllers.vrf; controller = ApiController.Vrf;
identifiers.Add(VrfId!.Value.ToString()); identifiers.Add(VrfId!.Value.ToString());
identifiers.Add("subnets"); identifiers.Add("subnets");
break; break;
case "ByVlanId": case "ByVlanId":
controller = controllers.vlan; controller = ApiController.Vlan;
identifiers.Add(VlanId!.Value.ToString()); identifiers.Add(VlanId!.Value.ToString());
identifiers.Add("subnets"); identifiers.Add("subnets");
if (SectionId.HasValue) AddSectionIdentifier(identifiers);
{
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; break;
case "ByVlanNumber": case "ByVlanNumber":
controller = controllers.vlan; controller = ApiController.Vlan;
var vlans = RequestHelper.InvokeRequest("GET", controllers.vlan, types.Vlan, null, null, new[] { "search", VlanNumber!.Value.ToString() }) var vlan = FindVlanByNumber(VlanNumber!.Value, VlanDomainId);
.GetAwaiter().GetResult(); identifiers.Add(vlan.Id.ToString());
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"); identifiers.Add("subnets");
if (SectionId.HasValue) AddSectionIdentifier(identifiers);
{
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; break;
} }
var result = RequestHelper.InvokeRequest("GET", controller, types.Subnetwork, null, null, identifiers.ToArray()) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", controller, ModelType.Subnetwork, null, null, identifiers.ToArray()
).GetAwaiter().GetResult();
if (result != null) WriteResult(result);
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteError(new ErrorRecord(ex, "GetSubnetError", ErrorCategory.InvalidOperation, null)); WriteError(new ErrorRecord(ex, "GetSubnetError", ErrorCategory.InvalidOperation, null));
} }
} }
private Section GetSectionByName(string name)
{
var section = RequestHelper.InvokeRequest(
"GET", ApiController.Sections, ModelType.Section, null, null, new[] { name }
).GetAwaiter().GetResult() as Section;
if (section == null)
{
throw new ItemNotFoundException($"Section '{name}' not found.");
}
return section;
}
private Vlan FindVlanByNumber(int number, int? domainId)
{
var vlans = RequestHelper.InvokeRequest(
"GET", ApiController.Vlan, ModelType.Vlan, null, null,
new[] { "search", number.ToString() }
).GetAwaiter().GetResult();
if (vlans == null)
{
throw new ItemNotFoundException($"VLAN {number} not found.");
}
Vlan? foundVlan = null;
if (vlans is System.Collections.IEnumerable enumerable)
{
foreach (var v in enumerable)
{
if (v is Vlan vlan)
{
if (domainId.HasValue && vlan.DomainId != domainId.Value)
{
continue;
}
if (foundVlan != null)
{
throw new InvalidOperationException(
$"Multiple VLANs with number {number} exist. Specify VlanDomainId to narrow the search.");
}
foundVlan = vlan;
}
}
}
if (foundVlan == null)
{
throw new ItemNotFoundException($"VLAN {number} not found.");
}
return foundVlan;
}
private void AddSectionIdentifier(List<string> identifiers)
{
if (SectionId.HasValue)
{
identifiers.Add(SectionId.Value.ToString());
}
else if (!string.IsNullOrEmpty(SectionName))
{
var section = GetSectionByName(SectionName);
identifiers.Add(section.Id.ToString());
}
}
} }

View File

@@ -1,20 +1,23 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves subnet usage statistics from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "SubnetUsage", DefaultParameterSetName = "ByID")] [Cmdlet(VerbsCommon.Get, "SubnetUsage", DefaultParameterSetName = "ByID")]
public class GetSubnetUsageCmdlet : PSCmdlet public class GetSubnetUsageCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByCIDR")] ParameterSetName = "ByCIDR",
HelpMessage = "The subnet in CIDR notation.")]
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")] [ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? CIDR { get; set; } public string? CIDR { get; set; }
@@ -24,43 +27,60 @@ public class GetSubnetUsageCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The subnet ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
Position = 0,
ParameterSetName = "BySubnetObject",
HelpMessage = "The subnet object.")]
[ValidateNotNullOrEmpty]
public Subnetwork? SubnetObject { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try try
{ {
int subnetId; var subnetId = GetSubnetId();
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 identifiers = new List<string> { subnetId.ToString(), "usage" };
var result = RequestHelper.InvokeRequest("GET", controllers.subnets, null, null, null, identifiers.ToArray())
.GetAwaiter().GetResult();
if (result != null) var result = RequestHelper.InvokeRequest(
{ "GET", ApiController.Subnets, null, null, null, identifiers.ToArray()
WriteObject(result); ).GetAwaiter().GetResult();
}
WriteResult(result);
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteError(new ErrorRecord(ex, "GetSubnetUsageError", ErrorCategory.InvalidOperation, null)); WriteError(new ErrorRecord(ex, "GetSubnetUsageError", ErrorCategory.InvalidOperation, null));
} }
} }
private int GetSubnetId()
{
switch (ParameterSetName)
{
case "ByCIDR":
var subnet = RequestHelper.InvokeRequest(
"GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
new[] { "cidr", CIDR! }
).GetAwaiter().GetResult() as Subnetwork;
if (subnet == null)
{
throw new ItemNotFoundException($"Subnet '{CIDR}' not found.");
}
return subnet.Id;
case "BySubnetObject":
return SubnetObject!.Id;
default:
return Id!.Value;
}
}
} }

View File

@@ -1,20 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves tag information from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Tag", DefaultParameterSetName = "NoParams")] [Cmdlet(VerbsCommon.Get, "Tag", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Tag))] [OutputType(typeof(Tag))]
public class GetTagCmdlet : PSCmdlet public class GetTagCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = false, Mandatory = false,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The tag ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -23,7 +27,8 @@ public class GetTagCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByAddressObject")] ParameterSetName = "ByAddressObject",
HelpMessage = "Get the tag associated with this address.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Address? AddressObject { get; set; } public Address? AddressObject { get; set; }
@@ -32,7 +37,8 @@ public class GetTagCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetObject")] ParameterSetName = "BySubnetObject",
HelpMessage = "Get the tag associated with this subnet.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Subnetwork? SubnetObject { get; set; } public Subnetwork? SubnetObject { get; set; }
@@ -50,6 +56,7 @@ public class GetTagCmdlet : PSCmdlet
identifiers.Add(Id.Value.ToString()); identifiers.Add(Id.Value.ToString());
} }
break; break;
case "ByAddressObject": case "ByAddressObject":
if (AddressObject?.TagId > 0) if (AddressObject?.TagId > 0)
{ {
@@ -60,6 +67,7 @@ public class GetTagCmdlet : PSCmdlet
return; return;
} }
break; break;
case "BySubnetObject": case "BySubnetObject":
if (SubnetObject?.TagId > 0) if (SubnetObject?.TagId > 0)
{ {
@@ -72,23 +80,11 @@ public class GetTagCmdlet : PSCmdlet
break; break;
} }
var result = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Tag, null, null, identifiers.ToArray()) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.Addresses, ModelType.Tag, null, null, identifiers.ToArray()
).GetAwaiter().GetResult();
if (result != null) WriteResult(result);
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,20 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves VLAN information from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Vlan", DefaultParameterSetName = "NoParams")] [Cmdlet(VerbsCommon.Get, "Vlan", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Vlan))] [OutputType(typeof(Vlan))]
public class GetVlanCmdlet : PSCmdlet public class GetVlanCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The VLAN ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -23,7 +27,8 @@ public class GetVlanCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByNumber")] ParameterSetName = "ByNumber",
HelpMessage = "The VLAN number.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Number { get; set; } public int? Number { get; set; }
@@ -32,7 +37,8 @@ public class GetVlanCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByL2Domain")] ParameterSetName = "ByL2Domain",
HelpMessage = "The L2 domain ID to get VLANs from.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? L2DomainId { get; set; } public int? L2DomainId { get; set; }
@@ -41,7 +47,8 @@ public class GetVlanCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetObject")] ParameterSetName = "BySubnetObject",
HelpMessage = "Get the VLAN associated with this subnet.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Subnetwork? SubnetObject { get; set; } public Subnetwork? SubnetObject { get; set; }
@@ -50,7 +57,8 @@ public class GetVlanCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByDomainObject")] ParameterSetName = "ByDomainObject",
HelpMessage = "Get VLANs in this L2 domain.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Domain? DomainObject { get; set; } public Domain? DomainObject { get; set; }
@@ -58,7 +66,7 @@ public class GetVlanCmdlet : PSCmdlet
{ {
try try
{ {
var controller = controllers.vlan; var controller = ApiController.Vlan;
var identifiers = new List<string>(); var identifiers = new List<string>();
switch (ParameterSetName) switch (ParameterSetName)
@@ -66,65 +74,44 @@ public class GetVlanCmdlet : PSCmdlet
case "ByID": case "ByID":
identifiers.Add(Id!.Value.ToString()); identifiers.Add(Id!.Value.ToString());
break; break;
case "ByNumber": case "ByNumber":
identifiers.Add("search"); identifiers.Add("search");
identifiers.Add(Number!.Value.ToString()); identifiers.Add(Number!.Value.ToString());
break; break;
case "ByL2Domain": case "ByL2Domain":
controller = controllers.l2domains; controller = ApiController.L2Domains;
identifiers.Add(L2DomainId!.Value.ToString()); identifiers.Add(L2DomainId!.Value.ToString());
identifiers.Add(subcontrollers.vlans.ToString()); identifiers.Add(ApiSubController.Vlans.ToString().ToLowerInvariant());
break; break;
case "BySubnetObject": case "BySubnetObject":
if (SubnetObject != null && SubnetObject.VlanId > 0) if (SubnetObject == null || SubnetObject.VlanId <= 0)
{
identifiers.Add(SubnetObject.VlanId.ToString());
}
else
{ {
return; return;
} }
identifiers.Add(SubnetObject.VlanId.ToString());
break; break;
case "ByDomainObject": case "ByDomainObject":
if (DomainObject != null) if (DomainObject != null)
{ {
var result = RequestHelper.InvokeRequest("GET", controllers.l2domains, types.Vlan, subcontrollers.vlans, null, new[] { DomainObject.Id.ToString() }) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.L2Domains, ModelType.Vlan, ApiSubController.Vlans,
if (result != null) null, new[] { DomainObject.Id.ToString() }
{ ).GetAwaiter().GetResult();
if (result is System.Collections.IEnumerable enumerable && !(result is string)) WriteResult(result);
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
return; return;
} }
var vlanResult = RequestHelper.InvokeRequest("GET", controller, types.Vlan, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null) var vlanResult = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", controller, ModelType.Vlan, null, null,
identifiers.Count > 0 ? identifiers.ToArray() : null
).GetAwaiter().GetResult();
if (vlanResult != null) WriteResult(vlanResult);
{
if (vlanResult is System.Collections.IEnumerable enumerable && !(vlanResult is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(vlanResult);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,20 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Retrieves VRF information from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Vrf", DefaultParameterSetName = "NoParams")] [Cmdlet(VerbsCommon.Get, "Vrf", DefaultParameterSetName = "NoParams")]
[OutputType(typeof(Vrf))] [OutputType(typeof(Vrf))]
public class GetVrfCmdlet : PSCmdlet public class GetVrfCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByID")] ParameterSetName = "ByID",
HelpMessage = "The VRF ID.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -23,28 +27,18 @@ public class GetVrfCmdlet : PSCmdlet
try try
{ {
var identifiers = new List<string>(); var identifiers = new List<string>();
if (Id.HasValue) if (Id.HasValue)
{ {
identifiers.Add(Id.Value.ToString()); identifiers.Add(Id.Value.ToString());
} }
var result = RequestHelper.InvokeRequest("GET", controllers.vrf, types.Vrf, null, null, identifiers.Count > 0 ? identifiers.ToArray() : null) var result = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.Vrf, ModelType.Vrf, null, null,
identifiers.Count > 0 ? identifiers.ToArray() : null
).GetAwaiter().GetResult();
if (result != null) WriteResult(result);
{
if (result is System.Collections.IEnumerable enumerable && !(result is string))
{
foreach (var item in enumerable)
{
WriteObject(item);
}
}
else
{
WriteObject(result);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,21 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Creates a new IP address entry in phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.New, "Address", DefaultParameterSetName = "BySubnetId")] [Cmdlet(VerbsCommon.New, "Address", DefaultParameterSetName = "BySubnetId")]
[OutputType(typeof(Address))] [OutputType(typeof(Address))]
public class NewAddressCmdlet : PSCmdlet public class NewAddressCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetId")] ParameterSetName = "BySubnetId",
HelpMessage = "The subnet ID to create the address in.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? SubnetId { get; set; } public int? SubnetId { get; set; }
@@ -24,7 +27,8 @@ public class NewAddressCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "BySubnetObject")] ParameterSetName = "BySubnetObject",
HelpMessage = "The subnet object to create the address in.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Subnetwork? SubnetObject { get; set; } public Subnetwork? SubnetObject { get; set; }
@@ -32,166 +36,73 @@ public class NewAddressCmdlet : PSCmdlet
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 1)] Position = 1,
HelpMessage = "The IP address to create.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string IP { get; set; } = string.Empty; public string IP { get; set; } = string.Empty;
[Parameter( [Parameter(Mandatory = false, Position = 2, HelpMessage = "Mark this address as a gateway.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2)]
public SwitchParameter Gateway { get; set; } public SwitchParameter Gateway { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 3, HelpMessage = "Description for the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 3)]
public string? Description { get; set; } public string? Description { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 4, HelpMessage = "Hostname for the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 4)]
public string? Hostname { get; set; } public string? Hostname { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 5, HelpMessage = "MAC address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 5)]
public string? MAC { get; set; } public string? MAC { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 6, HelpMessage = "Owner of the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 6)]
public string? Owner { get; set; } public string? Owner { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 7, HelpMessage = "Tag ID for the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 7)]
public int? TagId { get; set; } public int? TagId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 8, HelpMessage = "Ignore PTR record generation.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 8)]
public SwitchParameter PTRIgnore { get; set; } public SwitchParameter PTRIgnore { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 9, HelpMessage = "PTR record ID.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 7)]
public int? PTRId { get; set; } public int? PTRId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 10, HelpMessage = "Note for the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 10)]
public string? Note { get; set; } public string? Note { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 11, HelpMessage = "Exclude from ping scanning.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 11)]
public SwitchParameter ExcludePing { get; set; } public SwitchParameter ExcludePing { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 12, HelpMessage = "Associated device ID.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public int? DeviceId { get; set; } public int? DeviceId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 13, HelpMessage = "Port information.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 13)]
public string? Port { get; set; } public string? Port { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 14, HelpMessage = "Custom fields as a hashtable or PSObject.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 14)]
public object? CustomFields { get; set; } public object? CustomFields { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try try
{ {
int actualSubnetId; var actualSubnetId = ParameterSetName == "BySubnetObject"
if (ParameterSetName == "BySubnetObject") ? SubnetObject!.Id
{ : SubnetId!.Value;
actualSubnetId = SubnetObject!.Id;
}
else
{
actualSubnetId = SubnetId!.Value;
}
var body = new Dictionary<string, object> var body = BuildRequestBody(actualSubnetId);
{
{ "subnetId", actualSubnetId },
{ "ip", IP }
};
if (Gateway.IsPresent) var result = RequestHelper.InvokeRequest(
body["is_gateway"] = "1"; "POST", ApiController.Addresses, null, null, body
if (!string.IsNullOrEmpty(Description)) ).GetAwaiter().GetResult();
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) if (result != null)
{ {
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "search", IP }) // Fetch the created address to return it
.GetAwaiter().GetResult(); var address = RequestHelper.InvokeRequest(
if (address != null) "GET", ApiController.Addresses, ModelType.Address, null, null,
{ new[] { "search", IP }
WriteObject(address); ).GetAwaiter().GetResult();
}
WriteResult(address);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -200,20 +111,32 @@ public class NewAddressCmdlet : PSCmdlet
} }
} }
private Dictionary<string, object> ConvertCustomFields(object customFields) private Dictionary<string, object> BuildRequestBody(int subnetId)
{ {
var dict = new Dictionary<string, object>(); var body = new Dictionary<string, object>
if (customFields is PSObject psobj)
{ {
foreach (var prop in psobj.Properties) ["subnetId"] = subnetId,
{ ["ip"] = IP
dict[prop.Name] = prop.Value ?? new object(); };
}
} if (Gateway.IsPresent) body["is_gateway"] = "1";
else if (customFields is Dictionary<string, object> dictObj) if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
if (!string.IsNullOrEmpty(Hostname)) body["hostname"] = Hostname;
if (!string.IsNullOrEmpty(MAC)) body["mac"] = MAC;
if (!string.IsNullOrEmpty(Owner)) body["owner"] = Owner;
if (TagId.HasValue) body["tag"] = TagId.Value;
if (PTRIgnore.IsPresent) body["PTRignore"] = "1";
if (PTRId.HasValue) body["PTR"] = PTRId.Value;
if (!string.IsNullOrEmpty(Note)) body["note"] = Note;
if (ExcludePing.IsPresent) body["excludePing"] = "1";
if (DeviceId.HasValue) body["deviceId"] = DeviceId.Value;
if (!string.IsNullOrEmpty(Port)) body["port"] = Port;
foreach (var kvp in ConvertCustomFields(CustomFields))
{ {
return dictObj; body[kvp.Key] = kvp.Value;
} }
return dict;
return body;
} }
} }

View File

@@ -1,168 +1,85 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Creates a new address using the first available IP in a subnet.
/// </summary>
[Cmdlet(VerbsCommon.New, "FirstFreeIP")] [Cmdlet(VerbsCommon.New, "FirstFreeIP")]
[OutputType(typeof(Address))] [OutputType(typeof(Address))]
public class NewFirstFreeIPCmdlet : PSCmdlet public class NewFirstFreeIPCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0)] Position = 0,
HelpMessage = "The subnet ID to create the address in.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string SubnetId { get; set; } = string.Empty; public string SubnetId { get; set; } = string.Empty;
[Parameter( [Parameter(Mandatory = false, Position = 1, HelpMessage = "Mark this address as a gateway.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2)]
public SwitchParameter Gateway { get; set; } public SwitchParameter Gateway { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 2, HelpMessage = "Description for the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 3)]
public string? Description { get; set; } public string? Description { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 3, HelpMessage = "Hostname for the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 4)]
public string? Hostname { get; set; } public string? Hostname { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 4, HelpMessage = "MAC address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 5)]
public string? MAC { get; set; } public string? MAC { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 5, HelpMessage = "Owner of the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 6)]
public string? Owner { get; set; } public string? Owner { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 6, HelpMessage = "Tag ID for the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 7)]
public string? TagId { get; set; } public string? TagId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 7, HelpMessage = "Ignore PTR record generation.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 8)]
public SwitchParameter PTRIgnore { get; set; } public SwitchParameter PTRIgnore { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 8, HelpMessage = "PTR record ID.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 9)]
public string? PTRId { get; set; } public string? PTRId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 9, HelpMessage = "Note for the address.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 10)]
public string? Note { get; set; } public string? Note { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 10, HelpMessage = "Exclude from ping scanning.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 11)]
public SwitchParameter ExcludePing { get; set; } public SwitchParameter ExcludePing { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 11, HelpMessage = "Associated device ID.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public string? DeviceId { get; set; } public string? DeviceId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 12, HelpMessage = "Port information.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 13)]
public string? Port { get; set; } public string? Port { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Custom fields as a hashtable or PSObject.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
public object? CustomFields { get; set; } public object? CustomFields { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try try
{ {
var identifiers = new List<string> { "first_free" }; var identifiers = new[] { "first_free" };
var body = new Dictionary<string, object> var body = BuildRequestBody();
{
{ "subnetId", SubnetId }
};
if (Gateway.IsPresent) var result = RequestHelper.InvokeRequest(
body["is_gateway"] = "1"; "POST", ApiController.Addresses, null, null, body, identifiers
if (!string.IsNullOrEmpty(Description)) ).GetAwaiter().GetResult();
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) if (result != null)
{ {
var ip = result.ToString(); var ip = result.ToString();
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, new[] { "search", ip }) var address = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.Addresses, ModelType.Address, null, null,
if (address != null) new[] { "search", ip! }
{ ).GetAwaiter().GetResult();
WriteObject(address);
} WriteResult(address);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -171,20 +88,31 @@ public class NewFirstFreeIPCmdlet : PSCmdlet
} }
} }
private Dictionary<string, object> ConvertCustomFields(object customFields) private Dictionary<string, object> BuildRequestBody()
{ {
var dict = new Dictionary<string, object>(); var body = new Dictionary<string, object>
if (customFields is PSObject psobj)
{ {
foreach (var prop in psobj.Properties) ["subnetId"] = SubnetId
{ };
dict[prop.Name] = prop.Value ?? new object();
} if (Gateway.IsPresent) body["is_gateway"] = "1";
} if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
else if (customFields is Dictionary<string, object> dictObj) if (!string.IsNullOrEmpty(Hostname)) body["hostname"] = Hostname;
if (!string.IsNullOrEmpty(MAC)) body["mac"] = MAC;
if (!string.IsNullOrEmpty(Owner)) body["owner"] = Owner;
if (!string.IsNullOrEmpty(TagId)) body["tag"] = TagId;
if (PTRIgnore.IsPresent) body["PTRignore"] = "1";
if (!string.IsNullOrEmpty(PTRId)) body["PTR"] = PTRId;
if (!string.IsNullOrEmpty(Note)) body["note"] = Note;
if (ExcludePing.IsPresent) body["excludePing"] = "1";
if (!string.IsNullOrEmpty(DeviceId)) body["deviceId"] = DeviceId;
if (!string.IsNullOrEmpty(Port)) body["port"] = Port;
foreach (var kvp in ConvertCustomFields(CustomFields))
{ {
return dictObj; body[kvp.Key] = kvp.Value;
} }
return dict;
return body;
} }
} }

View File

@@ -1,18 +1,22 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Management.Automation; using System.Management.Automation;
using System.Threading.Tasks;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Creates a new phpIPAM API session.
/// </summary>
[Cmdlet(VerbsCommon.New, "Session", DefaultParameterSetName = "Credentials")] [Cmdlet(VerbsCommon.New, "Session", DefaultParameterSetName = "Credentials")]
public class NewSessionCmdlet : PSCmdlet [OutputType(typeof(Session))]
public class NewSessionCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0)] Position = 0,
HelpMessage = "The phpIPAM server URL (must start with http:// or https://).")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
[ValidatePattern("^https?://")] [ValidatePattern("^https?://")]
public string URL { get; set; } = string.Empty; public string URL { get; set; } = string.Empty;
@@ -21,7 +25,8 @@ public class NewSessionCmdlet : PSCmdlet
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 1)] Position = 1,
HelpMessage = "The API application ID configured in phpIPAM.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string AppID { get; set; } = string.Empty; public string AppID { get; set; } = string.Empty;
@@ -30,7 +35,8 @@ public class NewSessionCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 2, Position = 2,
ParameterSetName = "Credentials")] ParameterSetName = "Credentials",
HelpMessage = "The credentials (username and password) for authentication.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public PSCredential? Credentials { get; set; } public PSCredential? Credentials { get; set; }
@@ -39,7 +45,8 @@ public class NewSessionCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 2, Position = 2,
ParameterSetName = "Token")] ParameterSetName = "Token",
HelpMessage = "The static API token for authentication.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string? Token { get; set; } public string? Token { get; set; }
@@ -47,7 +54,8 @@ public class NewSessionCmdlet : PSCmdlet
Mandatory = false, Mandatory = false,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 3)] Position = 3,
HelpMessage = "If specified, SSL certificate errors will be ignored.")]
public SwitchParameter IgnoreSSL { get; set; } public SwitchParameter IgnoreSSL { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
@@ -55,9 +63,10 @@ public class NewSessionCmdlet : PSCmdlet
try try
{ {
Session session; Session session;
if (ParameterSetName == "Credentials" && Credentials != null) if (ParameterSetName == "Credentials" && Credentials != null)
{ {
session = SessionManager.CreateSessionWithCredentials( session = SessionManager.CreateSessionWithCredentialsAsync(
URL, URL,
AppID, AppID,
Credentials, Credentials,
@@ -70,12 +79,14 @@ public class NewSessionCmdlet : PSCmdlet
} }
else else
{ {
throw new ArgumentException("Invalid parameter set"); throw new ArgumentException("Invalid parameter set. Provide either Credentials or Token.");
} }
WriteObject(session);
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteError(new ErrorRecord(ex, "NewSessionError", ErrorCategory.InvalidOperation, null)); WriteError(new ErrorRecord(ex, "NewSessionError", ErrorCategory.AuthenticationError, null));
} }
} }
} }

View File

@@ -1,20 +1,23 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using System.Net;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Creates a new subnet in phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.New, "Subnet")] [Cmdlet(VerbsCommon.New, "Subnet")]
[OutputType(typeof(Subnetwork))] [OutputType(typeof(Subnetwork))]
public class NewSubnetCmdlet : PSCmdlet public class NewSubnetCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0)] Position = 0,
HelpMessage = "The subnet in CIDR notation (e.g., 192.168.1.0/24).")]
[ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")] [ValidatePattern(@"^\d+\.\d+\.\d+\.\d+/\d{1,2}$")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string CIDR { get; set; } = string.Empty; public string CIDR { get; set; } = string.Empty;
@@ -23,187 +26,79 @@ public class NewSubnetCmdlet : PSCmdlet
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 1)] Position = 1,
HelpMessage = "The section ID to create the subnet in.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int SectionId { get; set; } public int SectionId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 2, HelpMessage = "Description for the subnet.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 2)]
public string? Description { get; set; } public string? Description { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 3, HelpMessage = "VLAN ID to associate.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 3)]
public int? VlanId { get; set; } public int? VlanId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 4, HelpMessage = "VRF ID to associate.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 4)]
public int? VrfId { get; set; } public int? VrfId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 5, HelpMessage = "Master subnet ID for hierarchy.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 5)]
public int? MasterSubnetId { get; set; } public int? MasterSubnetId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 6, HelpMessage = "Nameserver ID.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 6)]
public int? NameserverId { get; set; } public int? NameserverId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 7, HelpMessage = "Show subnet name.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 7)]
public SwitchParameter ShowName { get; set; } public SwitchParameter ShowName { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 8, HelpMessage = "Enable recursive DNS.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 8)]
public SwitchParameter DNSRecursive { get; set; } public SwitchParameter DNSRecursive { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 9, HelpMessage = "Enable DNS records.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 9)]
public SwitchParameter DNSRecords { get; set; } public SwitchParameter DNSRecords { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 10, HelpMessage = "Allow IP requests.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 10)]
public SwitchParameter AllowRequests { get; set; } public SwitchParameter AllowRequests { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 11, HelpMessage = "Scan agent ID.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 11)]
public int? ScanAgentId { get; set; } public int? ScanAgentId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 12, HelpMessage = "Enable subnet discovery.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public SwitchParameter DiscoverSubnet { get; set; } public SwitchParameter DiscoverSubnet { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 13, HelpMessage = "Mark subnet as full.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public SwitchParameter IsFull { get; set; } public SwitchParameter IsFull { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 14, HelpMessage = "Tag ID for the subnet.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 12)]
public int? TagId { get; set; } public int? TagId { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 15, HelpMessage = "Usage threshold percentage (1-100).")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 13)]
[ValidateRange(1, 100)] [ValidateRange(1, 100)]
public int? Threshold { get; set; } public int? Threshold { get; set; }
[Parameter( [Parameter(Mandatory = false, Position = 16, HelpMessage = "Location ID.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 14)]
public int? LocationId { get; set; } public int? LocationId { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Custom fields as a hashtable or PSObject.")]
Mandatory = false,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
Position = 15)]
public object? CustomFields { get; set; } public object? CustomFields { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try try
{ {
var parts = CIDR.Split('/'); var body = BuildRequestBody();
var body = new Dictionary<string, object>
{
{ "subnet", parts[0] },
{ "mask", parts[1] },
{ "sectionId", SectionId }
};
if (!string.IsNullOrEmpty(Description)) var result = RequestHelper.InvokeRequest(
body["description"] = Description; "POST", ApiController.Subnets, null, null, body
if (VlanId.HasValue) ).GetAwaiter().GetResult();
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) if (result != null)
{ {
// Get the created subnet // Get the created subnet
var subnet = RequestHelper.InvokeRequest("GET", controllers.subnets, types.Subnetwork, null, null, new[] { "cidr", CIDR }) var subnet = RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "GET", ApiController.Subnets, ModelType.Subnetwork, null, null,
if (subnet != null) new[] { "cidr", CIDR }
{ ).GetAwaiter().GetResult();
WriteObject(subnet);
} WriteResult(subnet);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -212,20 +107,37 @@ public class NewSubnetCmdlet : PSCmdlet
} }
} }
private Dictionary<string, object> ConvertCustomFields(object customFields) private Dictionary<string, object> BuildRequestBody()
{ {
var dict = new Dictionary<string, object>(); var parts = CIDR.Split('/');
if (customFields is PSObject psobj) var body = new Dictionary<string, object>
{ {
foreach (var prop in psobj.Properties) ["subnet"] = parts[0],
{ ["mask"] = parts[1],
dict[prop.Name] = prop.Value ?? new object(); ["sectionId"] = SectionId
} };
}
else if (customFields is Dictionary<string, object> dictObj) if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
if (VlanId.HasValue) body["vlanId"] = VlanId.Value;
if (VrfId.HasValue) body["vrfId"] = VrfId.Value;
if (MasterSubnetId.HasValue) body["masterSubnetId"] = MasterSubnetId.Value;
if (NameserverId.HasValue) body["nameserverId"] = NameserverId.Value;
if (ShowName.IsPresent) body["showName"] = "1";
if (DNSRecursive.IsPresent) body["DNSrecursive"] = "1";
if (DNSRecords.IsPresent) body["DNSrecords"] = "1";
if (AllowRequests.IsPresent) body["allowRequests"] = "1";
if (ScanAgentId.HasValue) body["scanAgent"] = ScanAgentId.Value;
if (DiscoverSubnet.IsPresent) body["discoverSubnet"] = "1";
if (IsFull.IsPresent) body["isFull"] = "1";
if (TagId.HasValue) body["state"] = TagId.Value;
if (Threshold.HasValue) body["threshold"] = Threshold.Value;
if (LocationId.HasValue) body["location"] = LocationId.Value;
foreach (var kvp in ConvertCustomFields(CustomFields))
{ {
return dictObj; body[kvp.Key] = kvp.Value;
} }
return dict;
return body;
} }
} }

View File

@@ -1,27 +1,31 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
[Cmdlet(VerbsCommon.Remove, "Address", DefaultParameterSetName = "ByID")] /// <summary>
public class RemoveAddressCmdlet : PSCmdlet /// Removes an IP address entry from phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Remove, "Address", DefaultParameterSetName = "ById", SupportsShouldProcess = true)]
public class RemoveAddressCmdlet : BaseCmdlet
{ {
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
Position = 0,
ParameterSetName = "ByID")]
[ValidateNotNullOrEmpty]
public int? Id { get; set; }
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByAddressObject")] ParameterSetName = "ById",
HelpMessage = "The address ID to remove.")]
[ValidateNotNullOrEmpty]
public int Id { get; set; }
[Parameter(
Mandatory = true,
ValueFromPipeline = true,
Position = 0,
ParameterSetName = "ByAddressObject",
HelpMessage = "The address object to remove.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Address? AddressObject { get; set; } public Address? AddressObject { get; set; }
@@ -29,19 +33,17 @@ public class RemoveAddressCmdlet : PSCmdlet
{ {
try try
{ {
int addressId; var addressId = ParameterSetName == "ById" ? Id : AddressObject!.Id;
if (ParameterSetName == "ByID") var identifiers = new[] { addressId.ToString() };
{
addressId = Id!.Value;
}
else
{
addressId = AddressObject!.Id;
}
var identifiers = new List<string> { addressId.ToString() }; if (ShouldProcess($"Address ID: {addressId}", "Remove"))
RequestHelper.InvokeRequest("DELETE", controllers.addresses, null, null, null, identifiers.ToArray()) {
.GetAwaiter().GetResult(); RequestHelper.InvokeRequest(
"DELETE", ApiController.Addresses, null, null, null, identifiers
).GetAwaiter().GetResult();
WriteVerbose($"Address {addressId} removed successfully.");
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -1,20 +1,24 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Updates an existing IP address entry in phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Set, "Address", DefaultParameterSetName = "ById")] [Cmdlet(VerbsCommon.Set, "Address", DefaultParameterSetName = "ById")]
[OutputType(typeof(Address))] [OutputType(typeof(Address))]
public class SetAddressCmdlet : PSCmdlet public class SetAddressCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ById")] ParameterSetName = "ById",
HelpMessage = "The address ID to update.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int? Id { get; set; } public int? Id { get; set; }
@@ -23,142 +27,72 @@ public class SetAddressCmdlet : PSCmdlet
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0, Position = 0,
ParameterSetName = "ByAddressObject")] ParameterSetName = "ByAddressObject",
HelpMessage = "The address object to update.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public Address? AddressObject { get; set; } public Address? AddressObject { get; set; }
[Parameter( [Parameter(Position = 1, HelpMessage = "Set as gateway address.")]
Position = 1,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = "ById")]
public bool? Gateway { get; set; } public bool? Gateway { get; set; }
[Parameter( [Parameter(Position = 2, HelpMessage = "Description for the address.")]
Position = 2,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = "ById")]
public string? Description { get; set; } public string? Description { get; set; }
[Parameter( [Parameter(Position = 3, HelpMessage = "Hostname for the address.")]
Mandatory = false,
Position = 3)]
public string? Hostname { get; set; } public string? Hostname { get; set; }
[Parameter( [Parameter(Position = 4, HelpMessage = "MAC address.")]
Mandatory = false,
Position = 4)]
public string? MAC { get; set; } public string? MAC { get; set; }
[Parameter( [Parameter(Position = 5, HelpMessage = "Owner of the address.")]
Mandatory = false,
Position = 5)]
public string? Owner { get; set; } public string? Owner { get; set; }
[Parameter( [Parameter(Position = 6, HelpMessage = "Tag ID for the address.")]
Mandatory = false,
Position = 6)]
public int? TagId { get; set; } public int? TagId { get; set; }
[Parameter( [Parameter(Position = 7, HelpMessage = "Ignore PTR record generation.")]
Mandatory = false,
Position = 7)]
public bool? PTRIgnore { get; set; } public bool? PTRIgnore { get; set; }
[Parameter( [Parameter(Position = 8, HelpMessage = "PTR record ID.")]
Mandatory = false,
Position = 8)]
public int? PTRId { get; set; } public int? PTRId { get; set; }
[Parameter( [Parameter(Position = 9, HelpMessage = "Note for the address.")]
Mandatory = false,
Position = 9)]
public string? Note { get; set; } public string? Note { get; set; }
[Parameter( [Parameter(Position = 10, HelpMessage = "Exclude from ping scanning.")]
Mandatory = false,
Position = 10)]
public bool? ExcludePing { get; set; } public bool? ExcludePing { get; set; }
[Parameter( [Parameter(Position = 11, HelpMessage = "Associated device ID.")]
Mandatory = false,
Position = 11)]
public int? DeviceId { get; set; } public int? DeviceId { get; set; }
[Parameter( [Parameter(Position = 12, HelpMessage = "Port information.")]
Mandatory = false,
Position = 12)]
public string? Port { get; set; } public string? Port { get; set; }
[Parameter( [Parameter(HelpMessage = "Custom fields as a hashtable or PSObject.")]
Mandatory = false)]
public object? CustomFields { get; set; } public object? CustomFields { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try try
{ {
int addressId; var addressId = ParameterSetName == "ById" ? Id!.Value : AddressObject!.Id;
if (ParameterSetName == "ById") var identifiers = new[] { addressId.ToString() };
{ var body = BuildRequestBody();
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 try
{ {
RequestHelper.InvokeRequest("PATCH", controllers.addresses, null, null, body, identifiers.ToArray()) RequestHelper.InvokeRequest(
.GetAwaiter().GetResult(); "PATCH", ApiController.Addresses, null, null, body, identifiers
).GetAwaiter().GetResult();
} }
finally finally
{ {
var address = RequestHelper.InvokeRequest("GET", controllers.addresses, types.Address, null, null, identifiers.ToArray()) // Always return the updated address
.GetAwaiter().GetResult(); var address = RequestHelper.InvokeRequest(
if (address != null) "GET", ApiController.Addresses, ModelType.Address, null, null, identifiers
{ ).GetAwaiter().GetResult();
WriteObject(address);
} WriteResult(address);
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -167,20 +101,28 @@ public class SetAddressCmdlet : PSCmdlet
} }
} }
private Dictionary<string, object> ConvertCustomFields(object customFields) private Dictionary<string, object> BuildRequestBody()
{ {
var dict = new Dictionary<string, object>(); var body = new Dictionary<string, object>();
if (customFields is PSObject psobj)
if (Gateway.HasValue) body["is_gateway"] = Gateway.Value;
if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
if (!string.IsNullOrEmpty(Hostname)) body["hostname"] = Hostname;
if (!string.IsNullOrEmpty(MAC)) body["mac"] = MAC;
if (!string.IsNullOrEmpty(Owner)) body["owner"] = Owner;
if (TagId.HasValue) body["tag"] = TagId.Value;
if (PTRIgnore.HasValue) body["PTRignore"] = PTRIgnore.Value;
if (PTRId.HasValue) body["PTR"] = PTRId.Value;
if (!string.IsNullOrEmpty(Note)) body["note"] = Note;
if (ExcludePing.HasValue) body["excludePing"] = ExcludePing.Value;
if (DeviceId.HasValue) body["deviceId"] = DeviceId.Value;
if (!string.IsNullOrEmpty(Port)) body["port"] = Port;
foreach (var kvp in ConvertCustomFields(CustomFields))
{ {
foreach (var prop in psobj.Properties) body[kvp.Key] = kvp.Value;
{
dict[prop.Name] = prop.Value ?? new object();
}
} }
else if (customFields is Dictionary<string, object> dictObj)
{ return body;
return dictObj;
}
return dict;
} }
} }

View File

@@ -1,143 +1,91 @@
namespace PS.IPAM.Cmdlets; namespace PS.IPAM.Cmdlets;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Management.Automation; using System.Management.Automation;
using PS.IPAM;
using PS.IPAM.Helpers; using PS.IPAM.Helpers;
/// <summary>
/// Updates an existing subnet in phpIPAM.
/// </summary>
[Cmdlet(VerbsCommon.Set, "Subnet")] [Cmdlet(VerbsCommon.Set, "Subnet")]
[OutputType(typeof(Subnetwork))] [OutputType(typeof(Subnetwork))]
public class SetSubnetCmdlet : PSCmdlet public class SetSubnetCmdlet : BaseCmdlet
{ {
[Parameter( [Parameter(
Mandatory = true, Mandatory = true,
ValueFromPipeline = true, ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true, ValueFromPipelineByPropertyName = true,
Position = 0)] Position = 0,
HelpMessage = "The subnet ID to update.")]
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public int Id { get; set; } public int Id { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Description for the subnet.")]
Mandatory = false)]
public string? Description { get; set; } public string? Description { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "VLAN ID to associate.")]
Mandatory = false)]
public int? VlanId { get; set; } public int? VlanId { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "VRF ID to associate.")]
Mandatory = false)]
public int? VrfId { get; set; } public int? VrfId { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Master subnet ID for hierarchy.")]
Mandatory = false)]
public int? MasterSubnetId { get; set; } public int? MasterSubnetId { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Nameserver ID.")]
Mandatory = false)]
public int? NameserverId { get; set; } public int? NameserverId { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Show subnet name.")]
Mandatory = false)]
public SwitchParameter ShowName { get; set; } public SwitchParameter ShowName { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Enable recursive DNS.")]
Mandatory = false)]
public SwitchParameter DNSRecursive { get; set; } public SwitchParameter DNSRecursive { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Enable DNS records.")]
Mandatory = false)]
public SwitchParameter DNSRecords { get; set; } public SwitchParameter DNSRecords { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Allow IP requests.")]
Mandatory = false)]
public SwitchParameter AllowRequests { get; set; } public SwitchParameter AllowRequests { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Scan agent ID.")]
Mandatory = false)]
public int? ScanAgentId { get; set; } public int? ScanAgentId { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Enable subnet discovery.")]
Mandatory = false)]
public SwitchParameter DiscoverSubnet { get; set; } public SwitchParameter DiscoverSubnet { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Mark subnet as full.")]
Mandatory = false)]
public SwitchParameter IsFull { get; set; } public SwitchParameter IsFull { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Tag ID for the subnet.")]
Mandatory = false)]
public int? TagId { get; set; } public int? TagId { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Usage threshold percentage (1-100).")]
Mandatory = false)]
[ValidateRange(1, 100)] [ValidateRange(1, 100)]
public int? Threshold { get; set; } public int? Threshold { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Location ID.")]
Mandatory = false)]
public int? LocationId { get; set; } public int? LocationId { get; set; }
[Parameter( [Parameter(Mandatory = false, HelpMessage = "Custom fields as a hashtable or PSObject.")]
Mandatory = false)]
public object? CustomFields { get; set; } public object? CustomFields { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
try try
{ {
var identifiers = new List<string> { Id.ToString() }; var identifiers = new[] { Id.ToString() };
var body = new Dictionary<string, object>(); var body = BuildRequestBody();
if (!string.IsNullOrEmpty(Description)) RequestHelper.InvokeRequest(
body["description"] = Description; "PATCH", ApiController.Subnets, null, null, body, identifiers
if (VlanId.HasValue) ).GetAwaiter().GetResult();
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 subnet = RequestHelper.InvokeRequest(
{ "GET", ApiController.Subnets, ModelType.Subnetwork, null, null, identifiers
var customDict = ConvertCustomFields(CustomFields); ).GetAwaiter().GetResult();
foreach (var kvp in customDict)
{
body[kvp.Key] = kvp.Value;
}
}
RequestHelper.InvokeRequest("PATCH", controllers.subnets, null, null, body, identifiers.ToArray()) WriteResult(subnet);
.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) catch (Exception ex)
{ {
@@ -145,20 +93,31 @@ public class SetSubnetCmdlet : PSCmdlet
} }
} }
private Dictionary<string, object> ConvertCustomFields(object customFields) private Dictionary<string, object> BuildRequestBody()
{ {
var dict = new Dictionary<string, object>(); var body = new Dictionary<string, object>();
if (customFields is PSObject psobj)
if (!string.IsNullOrEmpty(Description)) body["description"] = Description;
if (VlanId.HasValue) body["vlanId"] = VlanId.Value;
if (VrfId.HasValue) body["vrfId"] = VrfId.Value;
if (MasterSubnetId.HasValue) body["masterSubnetId"] = MasterSubnetId.Value;
if (NameserverId.HasValue) body["nameserverId"] = NameserverId.Value;
if (ShowName.IsPresent) body["showName"] = "1";
if (DNSRecursive.IsPresent) body["DNSrecursive"] = "1";
if (DNSRecords.IsPresent) body["DNSrecords"] = "1";
if (AllowRequests.IsPresent) body["allowRequests"] = "1";
if (ScanAgentId.HasValue) body["scanAgent"] = ScanAgentId.Value;
if (DiscoverSubnet.IsPresent) body["discoverSubnet"] = "1";
if (IsFull.IsPresent) body["isFull"] = "1";
if (TagId.HasValue) body["state"] = TagId.Value;
if (Threshold.HasValue) body["threshold"] = Threshold.Value;
if (LocationId.HasValue) body["location"] = LocationId.Value;
foreach (var kvp in ConvertCustomFields(CustomFields))
{ {
foreach (var prop in psobj.Properties) body[kvp.Key] = kvp.Value;
{
dict[prop.Name] = prop.Value ?? new object();
}
} }
else if (customFields is Dictionary<string, object> dictObj)
{ return body;
return dictObj;
}
return dict;
} }
} }

View File

@@ -1,4 +1,5 @@
namespace PS.IPAM.Helpers; namespace PS.IPAM.Helpers;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -9,135 +10,259 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PS.IPAM;
/// <summary>
/// Helper class for making HTTP requests to the phpIPAM API.
/// </summary>
public static class RequestHelper public static class RequestHelper
{ {
// Handler for testing - allows injecting a mock HTTP handler /// <summary>
/// Handler for testing - allows injecting a mock HTTP handler.
/// </summary>
public static HttpMessageHandler? TestHttpHandler { get; set; } public static HttpMessageHandler? TestHttpHandler { get; set; }
public static async Task<object?> InvokeRequest( /// <summary>
string method, /// Invokes an HTTP request to the phpIPAM API.
controllers controller, /// </summary>
types? type = null, /// <param name="method">The HTTP method (GET, POST, PATCH, DELETE).</param>
subcontrollers? subController = null, /// <param name="controller">The API controller to call.</param>
/// <param name="modelType">The expected model type for response conversion.</param>
/// <param name="subController">Optional sub-controller for nested endpoints.</param>
/// <param name="parameters">Optional request body parameters.</param>
/// <param name="identifiers">Optional path identifiers.</param>
/// <param name="ignoreSsl">Whether to ignore SSL certificate errors.</param>
/// <returns>The deserialized response data, or null if not found.</returns>
public static async Task<object?> InvokeRequestAsync(
HttpMethod method,
ApiController controller,
ModelType? modelType = null,
ApiSubController? subController = null,
object? parameters = null, object? parameters = null,
string[]? identifiers = null, string[]? identifiers = null,
bool ignoreSsl = false) bool ignoreSsl = false)
{ {
var tokenStatus = SessionManager.TestSession(); EnsureValidSession();
if (tokenStatus == "NoToken")
var session = SessionManager.CurrentSession!;
var uri = BuildUri(session, controller, subController, identifiers);
using var client = SessionManager.CreateHttpClient(ignoreSsl, TestHttpHandler);
ConfigureClient(client, session);
var response = await SendRequestAsync(client, method, uri, parameters);
if (response == null)
{ {
throw new Exception("No session available!"); return null;
} }
if (tokenStatus == "Expired") var responseContent = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{ {
await UpdateSession(); if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
throw new HttpRequestException($"Request failed with status {response.StatusCode}");
} }
if (string.IsNullOrEmpty(responseContent))
{
return null;
}
return ParseResponse(responseContent, modelType);
}
/// <summary>
/// Overload for backward compatibility using string method names.
/// </summary>
public static Task<object?> InvokeRequest(
string method,
ApiController controller,
ModelType? modelType = null,
ApiSubController? subController = null,
object? parameters = null,
string[]? identifiers = null,
bool ignoreSsl = false)
{
var httpMethod = method.ToUpperInvariant() switch
{
"GET" => HttpMethod.Get,
"POST" => HttpMethod.Post,
"PATCH" => new HttpMethod("PATCH"),
"DELETE" => HttpMethod.Delete,
"PUT" => HttpMethod.Put,
_ => throw new ArgumentException($"Unsupported HTTP method: {method}", nameof(method))
};
return InvokeRequestAsync(httpMethod, controller, modelType, subController, parameters, identifiers, ignoreSsl);
}
/// <summary>
/// Refreshes an expired session.
/// </summary>
public static async Task RefreshSessionAsync()
{
var session = SessionManager.CurrentSession; var session = SessionManager.CurrentSession;
if (session == null) if (session == null)
{ {
throw new Exception("No session available!"); throw new InvalidOperationException("No session available!");
} }
var uri = $"{session.URL}/api/{session.AppID}/{controller}"; var status = SessionManager.GetSessionStatus();
if (subController != null) if (status == SessionStatus.Valid)
{ {
uri += $"/{subController}"; // Just refresh the token
await InvokeRequestAsync(new HttpMethod("PATCH"), ApiController.User);
return;
} }
if (identifiers != null && identifiers.Length > 0)
if (status == SessionStatus.Expired && session.Credentials is PSCredential creds)
{
await SessionManager.CreateSessionWithCredentialsAsync(
session.URL,
session.AppID,
creds,
false
);
}
}
private static void EnsureValidSession()
{
var status = SessionManager.GetSessionStatus();
switch (status)
{
case SessionStatus.NoSession:
throw new InvalidOperationException("No session available!");
case SessionStatus.Expired:
RefreshSessionAsync().GetAwaiter().GetResult();
break;
}
}
private static string BuildUri(
Session session,
ApiController controller,
ApiSubController? subController,
string[]? identifiers)
{
var controllerName = GetControllerName(controller);
var uri = $"{session.URL}/api/{session.AppID}/{controllerName}";
if (subController.HasValue)
{
uri += $"/{GetSubControllerName(subController.Value)}";
}
if (identifiers is { Length: > 0 })
{ {
uri += $"/{string.Join("/", identifiers)}/"; uri += $"/{string.Join("/", identifiers)}/";
} }
using var client = SessionManager.CreateHttpClient(ignoreSsl, TestHttpHandler); return uri;
}
private static string GetControllerName(ApiController controller) => controller switch
{
ApiController.User => "user",
ApiController.Vlan => "vlan",
ApiController.Subnets => "subnets",
ApiController.Addresses => "addresses",
ApiController.Sections => "sections",
ApiController.Vrf => "vrf",
ApiController.L2Domains => "l2domains",
ApiController.Tools => "tools",
_ => throw new ArgumentOutOfRangeException(nameof(controller))
};
private static string GetSubControllerName(ApiSubController subController) => subController switch
{
ApiSubController.Nameservers => "nameservers",
ApiSubController.Tags => "tags",
ApiSubController.Devices => "devices",
ApiSubController.DeviceTypes => "device_types",
ApiSubController.Vlans => "vlans",
ApiSubController.Vrfs => "vrfs",
ApiSubController.ScanAgents => "scanagents",
ApiSubController.Locations => "locations",
ApiSubController.Nat => "nat",
ApiSubController.Racks => "racks",
_ => throw new ArgumentOutOfRangeException(nameof(subController))
};
private static void ConfigureClient(HttpClient client, Session session)
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
switch (session.AuthType) switch (session.AuthType)
{ {
case AuthType.credentials: case AuthType.Credentials:
client.DefaultRequestHeaders.Add("token", session.Token); client.DefaultRequestHeaders.Add("token", session.Token);
break; break;
case AuthType.token: case AuthType.Token:
client.DefaultRequestHeaders.Add("phpipam-token", session.Token); client.DefaultRequestHeaders.Add("phpipam-token", session.Token);
break; break;
} }
}
HttpResponseMessage? response = null; private static async Task<HttpResponseMessage?> SendRequestAsync(
HttpClient client,
HttpMethod method,
string uri,
object? parameters)
{
try try
{ {
if (method == "GET") if (method == HttpMethod.Get)
{ {
response = await client.GetAsync(uri); return 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) if (method == HttpMethod.Delete)
{ {
return null; return await client.DeleteAsync(uri);
} }
var responseContent = await response.Content.ReadAsStringAsync(); var jsonContent = parameters != null ? JsonConvert.SerializeObject(parameters) : "{}";
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
if (!response.IsSuccessStatusCode) if (method == HttpMethod.Post)
{ {
if (response.StatusCode == System.Net.HttpStatusCode.NotFound) return await client.PostAsync(uri, content);
{
return null;
}
throw new HttpRequestException($"Request failed with status {response.StatusCode}");
} }
if (string.IsNullOrEmpty(responseContent)) // PATCH, PUT, etc.
{ var request = new HttpRequestMessage(method, uri) { Content = content };
return null; return await client.SendAsync(request);
}
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) catch (HttpRequestException ex) when (ex.Message.Contains("404"))
{ {
if (ex.Message.Contains("404")) return null;
{
return null;
}
throw;
} }
} }
private static object? ConvertToTypedObjects(dynamic jsonResponse, types type) private static object? ParseResponse(string responseContent, ModelType? modelType)
{
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(responseContent);
if (jsonResponse == null)
{
return null;
}
if (!modelType.HasValue)
{
return jsonResponse.data;
}
return ConvertToTypedObjects(jsonResponse, modelType.Value);
}
private static object? ConvertToTypedObjects(dynamic jsonResponse, ModelType modelType)
{ {
if (jsonResponse?.data == null) if (jsonResponse?.data == null)
{ {
@@ -147,228 +272,170 @@ public static class RequestHelper
var data = jsonResponse.data; var data = jsonResponse.data;
if (data is JArray array) if (data is JArray array)
{ {
return array.Select(item => ConvertSingleObject(item, type)).ToList(); return array.Select(item => ConvertSingleObject(item, modelType)).ToList();
}
else
{
return ConvertSingleObject(data, type);
} }
return ConvertSingleObject(data, modelType);
} }
private static object? ConvertSingleObject(dynamic item, types type) private static object? ConvertSingleObject(dynamic item, ModelType modelType)
{ {
var jobject = item as JObject; if (item is not JObject jobject)
if (jobject == null)
{ {
return null; return null;
} }
var customFields = ExtractCustomFields(jobject);
return modelType switch
{
ModelType.Address => CreateAddress(jobject, customFields),
ModelType.Vlan => CreateVlan(jobject, customFields),
ModelType.Subnetwork => CreateSubnetwork(jobject, customFields),
ModelType.Vrf => CreateVrf(jobject, customFields),
ModelType.Section => CreateSection(jobject),
ModelType.Tag => CreateTag(jobject),
ModelType.Nameserver => CreateNameserver(jobject),
ModelType.Domain => CreateDomain(jobject),
_ => jobject.ToObject<object>()
};
}
private static Dictionary<string, object>? ExtractCustomFields(JObject jobject)
{
var customFields = new Dictionary<string, object>(); var customFields = new Dictionary<string, object>();
foreach (var prop in jobject.Properties()) foreach (var prop in jobject.Properties().Where(p => p.Name.StartsWith("custom_")))
{ {
if (prop.Name.StartsWith("custom_")) customFields[prop.Name] = prop.Value?.ToObject<object>() ?? string.Empty;
{
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>();
} }
return customFields.Count > 0 ? customFields : null;
} }
private static Address CreateAddress(JObject jobject, Dictionary<string, object> customFields) #region Model Factory Methods
{
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) private static Address CreateAddress(JObject obj, Dictionary<string, object>? customFields) => new(
{ obj["id"]?.ToObject<int>() ?? 0,
return new Vlan( obj["subnetId"]?.ToObject<int>() ?? 0,
jobject["vlanId"]?.ToObject<int>() ?? 0, obj["ip"]?.ToString() ?? "",
jobject["domainId"]?.ToObject<int>() ?? 0, obj["is_gateway"]?.ToObject<bool>() ?? false,
jobject["name"]?.ToString() ?? "", obj["description"]?.ToString() ?? "",
jobject["number"]?.ToObject<int>() ?? 0, obj["hostname"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "", obj["mac"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>(), obj["owner"]?.ToString() ?? "",
jobject["customer_id"]?.ToObject<int>() ?? 0, obj["tag"]?.ToObject<int>() ?? 0,
customFields.Count > 0 ? customFields : null obj["deviceId"]?.ToObject<int>() ?? 0,
); obj["location"]?.ToString() ?? "",
} obj["port"]?.ToString() ?? "",
obj["note"]?.ToString() ?? "",
obj["lastSeen"]?.ToObject<DateTime?>(),
obj["excludePing"]?.ToObject<bool>() ?? false,
obj["PTRignore"]?.ToObject<bool>() ?? false,
obj["PTR"]?.ToObject<int>() ?? 0,
obj["firewallAddressObject"]?.ToString() ?? "",
obj["editDate"]?.ToObject<DateTime?>(),
obj["customer_id"]?.ToObject<int>() ?? 0,
customFields
);
private static Subnetwork CreateSubnetwork(JObject jobject, Dictionary<string, object> customFields) private static Vlan CreateVlan(JObject obj, Dictionary<string, object>? customFields) => new(
{ obj["vlanId"]?.ToObject<int>() ?? 0,
var props = jobject.Properties().ToList(); obj["domainId"]?.ToObject<int>() ?? 0,
return new Subnetwork( obj["name"]?.ToString() ?? "",
jobject["id"]?.ToObject<int>() ?? 0, obj["number"]?.ToObject<int>() ?? 0,
jobject["subnet"]?.ToString() ?? "", obj["description"]?.ToString() ?? "",
jobject["mask"]?.ToObject<int>() ?? 0, obj["editDate"]?.ToObject<DateTime?>(),
jobject["sectionId"]?.ToObject<int>() ?? 0, obj["customer_id"]?.ToObject<int>() ?? 0,
jobject["description"]?.ToString() ?? "", customFields
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) private static Subnetwork CreateSubnetwork(JObject obj, Dictionary<string, object>? customFields) => new(
{ obj["id"]?.ToObject<int>() ?? 0,
return new Vrf( obj["subnet"]?.ToString() ?? "",
jobject["id"]?.ToObject<int>() ?? 0, obj["mask"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "", obj["sectionId"]?.ToObject<int>() ?? 0,
jobject["rd"]?.ToString() ?? "", obj["description"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "", obj["linked_subnet"]?.ToString() ?? "",
jobject["sections"]?.ToString() ?? "", obj["firewallAddressObject"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>(), obj["vrfId"]?.ToObject<int>() ?? 0,
customFields.Count > 0 ? customFields : null obj["masterSubnetId"]?.ToObject<int>() ?? 0,
); obj["allowRequests"]?.ToObject<bool>() ?? false,
} obj["vlanId"]?.ToObject<int>() ?? 0,
obj["showName"]?.ToObject<bool>() ?? false,
obj["deviceId"]?.ToObject<int>() ?? 0,
obj["permissions"]?.ToString() ?? "",
obj["pingSubnet"]?.ToObject<bool>() ?? false,
obj["discoverSubnet"]?.ToObject<bool>() ?? false,
obj["resolveDNS"]?.ToObject<bool>() ?? false,
obj["DNSrecursive"]?.ToObject<bool>() ?? false,
obj["DNSrecords"]?.ToObject<bool>() ?? false,
obj["nameserverId"]?.ToObject<int>() ?? 0,
obj["scanAgent"]?.ToObject<bool>() ?? false,
obj["isFolder"]?.ToObject<bool>() ?? false,
obj["isFull"]?.ToObject<bool>() ?? false,
obj["isPool"]?.ToObject<bool>() ?? false,
obj["state"]?.ToObject<int>() ?? 0,
obj["threshold"]?.ToObject<int>() ?? 0,
obj["location"]?.ToObject<int>() ?? 0,
obj["editDate"]?.ToObject<DateTime?>(),
obj["lastScan"]?.ToObject<DateTime?>(),
obj["lastDiscovery"]?.ToObject<DateTime?>(),
obj["calculation"]?.ToObject<object>() ?? new object(),
customFields
);
private static Section CreateSection(JObject jobject) private static Vrf CreateVrf(JObject obj, Dictionary<string, object>? customFields) => new(
{ obj["id"]?.ToObject<int>() ?? 0,
return new Section( obj["name"]?.ToString() ?? "",
jobject["id"]?.ToObject<int>() ?? 0, obj["rd"]?.ToString() ?? "",
jobject["name"]?.ToString() ?? "", obj["description"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "", obj["sections"]?.ToString() ?? "",
jobject["masterSection"]?.ToObject<int>() ?? 0, obj["editDate"]?.ToObject<DateTime?>(),
jobject["permissions"]?.ToString() ?? "", customFields
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) private static Section CreateSection(JObject obj) => new(
{ obj["id"]?.ToObject<int>() ?? 0,
return new Tag( obj["name"]?.ToString() ?? "",
jobject["id"]?.ToObject<int>() ?? 0, obj["description"]?.ToString() ?? "",
jobject["type"]?.ToString() ?? "", obj["masterSection"]?.ToObject<int>() ?? 0,
jobject["showtag"]?.ToObject<bool>() ?? false, obj["permissions"]?.ToString() ?? "",
jobject["bgcolor"]?.ToString() ?? "", obj["strictMode"]?.ToObject<bool>() ?? false,
jobject["fgcolor"]?.ToString() ?? "", obj["subnetOrdering"]?.ToString() ?? "",
jobject["compress"]?.ToString() ?? "", obj["order"]?.ToObject<int>() ?? 0,
jobject["locked"]?.ToString() ?? "", obj["editDate"]?.ToObject<DateTime?>(),
jobject["updateTag"]?.ToObject<bool>() ?? false obj["showSubnet"]?.ToObject<bool>() ?? false,
); obj["showVlan"]?.ToObject<bool>() ?? false,
} obj["showVRF"]?.ToObject<bool>() ?? false,
obj["showSupernetOnly"]?.ToObject<bool>() ?? false,
obj["DNS"]?.ToObject<int>() ?? 0
);
private static Nameserver CreateNameserver(JObject jobject) private static Tag CreateTag(JObject obj) => new(
{ obj["id"]?.ToObject<int>() ?? 0,
return new Nameserver( obj["type"]?.ToString() ?? "",
jobject["id"]?.ToObject<int>() ?? 0, obj["showtag"]?.ToObject<bool>() ?? false,
jobject["name"]?.ToString() ?? "", obj["bgcolor"]?.ToString() ?? "",
jobject["nameservers"]?.ToString() ?? "", obj["fgcolor"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "", obj["compress"]?.ToString() ?? "",
jobject["permissions"]?.ToString() ?? "", obj["locked"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>() obj["updateTag"]?.ToObject<bool>() ?? false
); );
}
private static Domain CreateDomain(JObject jobject) private static Nameserver CreateNameserver(JObject obj) => new(
{ obj["id"]?.ToObject<int>() ?? 0,
return new Domain( obj["name"]?.ToString() ?? "",
jobject["id"]?.ToObject<int>() ?? 0, obj["nameservers"]?.ToString() ?? "",
jobject["name"]?.ToString() ?? "", obj["description"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "", obj["permissions"]?.ToString() ?? "",
jobject["sections"]?.ToString() ?? "" obj["editDate"]?.ToObject<DateTime?>()
); );
}
private static async Task UpdateSession() private static Domain CreateDomain(JObject obj) => new(
{ obj["id"]?.ToObject<int>() ?? 0,
var session = SessionManager.CurrentSession; obj["name"]?.ToString() ?? "",
if (session == null) obj["description"]?.ToString() ?? "",
{ obj["sections"]?.ToString() ?? ""
throw new Exception("No session available!"); );
}
var tokenStatus = SessionManager.TestSession(); #endregion
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

@@ -1,44 +1,60 @@
namespace PS.IPAM.Helpers; namespace PS.IPAM.Helpers;
using System; using System;
using System.Management.Automation; using System.Management.Automation;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json; using Newtonsoft.Json;
using PS.IPAM;
/// <summary>
/// Manages phpIPAM API sessions including creation, validation, and lifecycle.
/// </summary>
public static class SessionManager public static class SessionManager
{ {
private static Session? _currentSession; private static Session? _currentSession;
/// <summary>
/// Gets or sets the current active session.
/// </summary>
public static Session? CurrentSession public static Session? CurrentSession
{ {
get => _currentSession; get => _currentSession;
set => _currentSession = value; set => _currentSession = value;
} }
public static string TestSession() /// <summary>
/// Tests the current session status.
/// </summary>
/// <returns>The session status indicating validity or issues.</returns>
public static SessionStatus GetSessionStatus()
{ {
if (_currentSession == null) if (_currentSession == null)
{ {
return "NoToken"; return SessionStatus.NoSession;
} }
if (_currentSession.Expires == null) if (_currentSession.Expires == null)
{ {
return "Valid"; return SessionStatus.Valid;
} }
if (_currentSession.Expires < DateTime.Now) return _currentSession.Expires < DateTime.Now
{ ? SessionStatus.Expired
return "Expired"; : SessionStatus.Valid;
}
return "Valid";
} }
public static async Task<Session> CreateSessionWithCredentials( /// <summary>
/// Creates a new session using username/password credentials.
/// </summary>
/// <param name="url">The phpIPAM server URL.</param>
/// <param name="appId">The API application ID.</param>
/// <param name="credentials">The PowerShell credential object.</param>
/// <param name="ignoreSsl">Whether to ignore SSL certificate errors.</param>
/// <returns>The created session.</returns>
public static async Task<Session> CreateSessionWithCredentialsAsync(
string url, string url,
string appId, string appId,
PSCredential credentials, PSCredential credentials,
@@ -46,7 +62,7 @@ public static class SessionManager
{ {
var uri = $"{url}/api/{appId}/user"; var uri = $"{url}/api/{appId}/user";
var auth = Convert.ToBase64String( var auth = Convert.ToBase64String(
Encoding.UTF8.GetBytes($"{credentials.UserName}:{GetPassword(credentials)}")); Encoding.UTF8.GetBytes($"{credentials.UserName}:{GetPasswordString(credentials)}"));
using var client = CreateHttpClient(ignoreSsl); using var client = CreateHttpClient(ignoreSsl);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
@@ -58,14 +74,15 @@ public static class SessionManager
if (jsonResponse?.success != true) if (jsonResponse?.success != true)
{ {
throw new Exception(jsonResponse?.error?.ToString() ?? "Failed to create session"); throw new InvalidOperationException(
jsonResponse?.error?.ToString() ?? "Failed to create session");
} }
var token = jsonResponse.data.token.ToString(); var token = jsonResponse.data.token.ToString();
var expires = DateTime.Parse(jsonResponse.data.expires.ToString()); var expires = DateTime.Parse(jsonResponse.data.expires.ToString());
_currentSession = new Session( _currentSession = new Session(
AuthType.credentials, AuthType.Credentials,
token, token,
appId, appId,
url, url,
@@ -76,13 +93,17 @@ public static class SessionManager
return _currentSession; return _currentSession;
} }
public static Session CreateSessionWithToken( /// <summary>
string url, /// Creates a new session using a static API token.
string appId, /// </summary>
string token) /// <param name="url">The phpIPAM server URL.</param>
/// <param name="appId">The API application ID.</param>
/// <param name="token">The API token.</param>
/// <returns>The created session.</returns>
public static Session CreateSessionWithToken(string url, string appId, string token)
{ {
_currentSession = new Session( _currentSession = new Session(
AuthType.token, AuthType.Token,
token, token,
appId, appId,
url, url,
@@ -93,24 +114,20 @@ public static class SessionManager
return _currentSession; return _currentSession;
} }
/// <summary>
/// Closes the current session and clears session data.
/// </summary>
public static void CloseSession() public static void CloseSession()
{ {
_currentSession = null; _currentSession = null;
} }
private static string GetPassword(PSCredential credential) /// <summary>
{ /// Creates an HttpClient with optional SSL bypass.
var ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(credential.Password); /// </summary>
try /// <param name="ignoreSsl">Whether to ignore SSL certificate errors.</param>
{ /// <param name="handler">Optional custom message handler for testing.</param>
return System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr); /// <returns>A configured HttpClient instance.</returns>
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
}
}
public static HttpClient CreateHttpClient(bool ignoreSsl = false, HttpMessageHandler? handler = null) public static HttpClient CreateHttpClient(bool ignoreSsl = false, HttpMessageHandler? handler = null)
{ {
if (handler != null) if (handler != null)
@@ -122,10 +139,27 @@ public static class SessionManager
{ {
var sslHandler = new HttpClientHandler var sslHandler = new HttpClientHandler
{ {
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true ServerCertificateCustomValidationCallback = (_, _, _, _) => true
}; };
return new HttpClient(sslHandler); return new HttpClient(sslHandler);
} }
return new HttpClient(); return new HttpClient();
} }
/// <summary>
/// Extracts the plain text password from a PSCredential object.
/// </summary>
private static string GetPasswordString(PSCredential credential)
{
var ptr = Marshal.SecureStringToBSTR(credential.Password);
try
{
return Marshal.PtrToStringBSTR(ptr);
}
finally
{
Marshal.ZeroFreeBSTR(ptr);
}
}
} }

View File

@@ -1,77 +1,35 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
using System.Collections.Generic;
/// <summary>
/// Represents an IP address entry in phpIPAM.
/// </summary>
[Serializable] [Serializable]
public class Address { public sealed record Address(
public int Id { get; } int Id,
public int SubnetId { get; } int SubnetId,
public string Ip { get; } string Ip,
public bool IsGateway { get; } bool IsGateway,
public string Description { get; } string Description,
public string Hostname { get; } string Hostname,
public string MAC { get; } string MAC,
public string Owner { get; } string Owner,
public int TagId { get; } int TagId,
public int DeviceId { get; } int DeviceId,
public string Location { get; } string Location,
public string Port { get; } string Port,
public string Note { get; } string Note,
public DateTime? LastSeen { get; } DateTime? LastSeen,
public bool ExcludePing { get; } bool ExcludePing,
public bool PTRignore { get; } bool PTRIgnore,
public int PTR { get; } int PTR,
public string FirewallAddressObject { get; } string FirewallAddressObject,
public DateTime? EditDate { get; } DateTime? EditDate,
public int CustomerId { get; } int CustomerId,
public Object? ExtendedData { get; } Dictionary<string, object>? ExtendedData = null
)
public Address( {
int id, public override string ToString() => Ip;
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;
}
} }

View File

@@ -1,27 +1,17 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
/// <summary>
/// Represents an L2 domain in phpIPAM.
/// </summary>
[Serializable] [Serializable]
public class Domain { public sealed record Domain(
public int Id { get; } int Id,
public string Name { get; } string Name,
public string Description { get; } string Description,
public string Sections { get; } string Sections
)
public Domain ( {
int id, public override string ToString() => Name;
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

@@ -1,8 +1,13 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
/// <summary>
/// Represents a nameserver configuration in phpIPAM.
/// </summary>
[Serializable] [Serializable]
public class Nameserver { public sealed record Nameserver
{
public int Id { get; } public int Id { get; }
public string Name { get; } public string Name { get; }
public string[] NameServers { get; } public string[] NameServers { get; }
@@ -16,13 +21,15 @@ public class Nameserver {
string nameServers, string nameServers,
string description, string description,
string permissions, string permissions,
DateTime? editDate DateTime? editDate)
) { {
this.Id = id; Id = id;
this.Name = name; Name = name;
this.NameServers = nameServers.Split(new char[] {';'}); NameServers = nameServers?.Split(';', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
this.Description = description; Description = description;
this.Permissions = permissions; Permissions = permissions;
this.EditDate = editDate; EditDate = editDate;
} }
public override string ToString() => Name;
} }

View File

@@ -1,57 +1,27 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
/// <summary>
/// Represents a section in phpIPAM that organizes subnets.
/// </summary>
[Serializable] [Serializable]
public class Section { public sealed record Section(
public int Id { get; } int Id,
public string Name { get; } string Name,
public string Description { get; } string Description,
public int MasterSectionId { get; } int MasterSectionId,
public string Permissions { get; } string Permissions,
public bool StrictMode { get; } bool StrictMode,
public string SubnetOrdering { get; } string SubnetOrdering,
public int Order { get; } int Order,
public DateTime? EditDate { get; } DateTime? EditDate,
public bool ShowSubnet { get; } bool ShowSubnet,
public bool ShowVlan { get; } bool ShowVlan,
public bool ShowVRF { get; } bool ShowVRF,
public bool ShowSupernetOnly { get; } bool ShowSupernetOnly,
public int DNSId { get; } int DNSId
)
public Section ( {
int id, public override string ToString() => Name;
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;
}
} }

View File

@@ -1,33 +1,27 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
using System.Management.Automation;
/// <summary>
/// Represents an authenticated session with phpIPAM API.
/// </summary>
[Serializable] [Serializable]
public class Session { public sealed record Session(
public AuthType AuthType { get; } AuthType AuthType,
public string Token { get; set; } string Token,
public string AppID { get; } string AppID,
public string URL { get; } string URL,
public DateTime? Expires { get; set; } DateTime? Expires,
public object? Credentials { get; } object? Credentials
public Session( )
AuthType authType, {
string token, /// <summary>
string appId, /// Gets or sets the current authentication token.
string url, /// </summary>
DateTime? expires, public string Token { get; set; } = Token;
object? credentials
) {
AuthType = authType;
Token = token;
AppID = appId;
URL = url;
Expires = expires;
Credentials = credentials;
}
public override string ToString() /// <summary>
{ /// Gets or sets the token expiration time.
return base.ToString(); /// </summary>
} public DateTime? Expires { get; set; } = Expires;
} }

View File

@@ -1,114 +1,51 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
using System.Collections.Generic;
/// <summary>
/// Represents a subnet/network in phpIPAM.
/// </summary>
[Serializable] [Serializable]
public class Subnetwork { public sealed record Subnetwork(
public int Id { get; } int Id,
public string Subnet { get; } string Subnet,
public int Mask { get; } int Mask,
public int SectionId { get; } int SectionId,
public string Description { get; } string Description,
public string LinkedSubnet { get; } string LinkedSubnet,
public string FirewallAddressObject { get; } string FirewallAddressObject,
public int VrfId { get; } int VrfId,
public int MasterSubnetId { get; } int MasterSubnetId,
public bool AllowRequests { get; } bool AllowRequests,
public int VlanId { get; } int VlanId,
public bool ShowName { get; } bool ShowName,
public int DeviceId { get; } int DeviceId,
public string Permissions { get; } string Permissions,
public bool PingSubnet { get; } bool PingSubnet,
public bool DiscoverSubnet { get; } bool DiscoverSubnet,
public bool ResolveDNS { get; } bool ResolveDNS,
public bool DNSRecursive { get; } bool DNSRecursive,
public bool DNSRecords { get; } bool DNSRecords,
public int NameserverId { get; } int NameserverId,
public bool ScanAgent { get; } bool ScanAgent,
public bool IsFolder { get; } bool IsFolder,
public bool IsFull { get; } bool IsFull,
public bool IsPool { get; } bool IsPool,
public int TagId { get; } int TagId,
public int Threshold { get; } int Threshold,
public int LocationId { get; } int LocationId,
public DateTime? EditDate { get; } DateTime? EditDate,
public DateTime? LastScan { get; } DateTime? LastScan,
public DateTime? LastDiscovery { get; } DateTime? LastDiscovery,
public Object Calculation { get; } object Calculation,
public Object? ExtendedData { get; } Dictionary<string, object>? ExtendedData = null
public Subnetwork( )
int id, {
string subnet, /// <summary>
int mask, /// Gets the subnet in CIDR notation (e.g., "192.168.1.0/24").
int sectionId, /// </summary>
string description, public string CIDR => $"{Subnet}/{Mask}";
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() { public override string ToString() => CIDR;
return $"{this.Subnet}/{this.Mask}";
}
public override string ToString()
{
return this.GetCIDR();
}
} }

View File

@@ -1,45 +1,21 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
/// <summary>
/// Represents an address tag in phpIPAM.
/// </summary>
[Serializable] [Serializable]
public class Tag { public sealed record Tag(
public int Id { get; } int Id,
public string Type { get; } string Type,
public bool ShowTag { get; } bool ShowTag,
public string BGColor { get; } string BackgroundColor,
public string FGColor { get; } string ForegroundColor,
public bool Compress { get; } string Compress,
public bool Locked { get; } string Locked,
public bool UpdateTag { get; } bool UpdateTag
)
public Tag( {
int id, public override string ToString() => Type;
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;
}
} }

View File

@@ -1,41 +1,27 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
using System.Dynamic; using System.Collections.Generic;
/// <summary>
/// Represents a VLAN in phpIPAM.
/// </summary>
[Serializable] [Serializable]
public class Vlan : DynamicObject { public sealed record Vlan(
public int Id { get; } int Id,
public int VlanId { get; } int DomainId,
public int DomainId { get; } string Name,
public string Name { get; } int Number,
public int Number { get; } string Description,
public string Description { get; } DateTime? EditDate,
public DateTime? EditDate { get; } int CustomerId,
public int CustomerId { get; } Dictionary<string, object>? ExtendedData = null
public Object? ExtendedData { get; } )
public Vlan ( {
int vlanId, /// <summary>
int domainId, /// Alias for Id to maintain API compatibility.
string name, /// </summary>
int number, public int VlanId => Id;
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() public override string ToString() => Number.ToString();
{
return $"{this.Number}";
}
} }

View File

@@ -1,35 +1,21 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
using System.Collections.Generic;
/// <summary>
/// Represents a VRF (Virtual Routing and Forwarding) instance in phpIPAM.
/// </summary>
[Serializable] [Serializable]
public class Vrf { public sealed record Vrf(
public int Id { get; } int Id,
public string Name { get; } string Name,
public string RouteDistinguisher { get; } string RouteDistinguisher,
public string Description { get; } string Description,
public string Sections { get; } string Sections,
public DateTime? EditDate { get; } DateTime? EditDate,
public Object? ExtendedData { get; } Dictionary<string, object>? ExtendedData = null
)
public Vrf( {
int id, public override string ToString() => Name;
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;
}
} }

View File

@@ -1,8 +1,20 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
/// <summary>
/// Specifies the authentication method for phpIPAM API.
/// </summary>
[Serializable] [Serializable]
public enum AuthType { public enum AuthType
credentials, {
token /// <summary>
/// Authentication using username and password credentials.
/// </summary>
Credentials,
/// <summary>
/// Authentication using a static API token.
/// </summary>
Token
} }

View File

@@ -1,14 +1,19 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
/// <summary>
/// Represents the main API controllers in phpIPAM.
/// </summary>
[Serializable] [Serializable]
public enum controllers { public enum ApiController
user, {
vlan, User,
subnets, Vlan,
addresses, Subnets,
sections, Addresses,
vrf, Sections,
l2domains, Vrf,
tools L2Domains,
Tools
} }

View File

@@ -1,16 +1,21 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
/// <summary>
/// Represents sub-controllers/endpoints within main API controllers.
/// </summary>
[Serializable] [Serializable]
public enum subcontrollers { public enum ApiSubController
nameservers, {
tags, Nameservers,
devices, Tags,
device_types, Devices,
vlans, DeviceTypes,
vrfs, Vlans,
scanagents, Vrfs,
locations, ScanAgents,
nat, Locations,
racks Nat,
Racks
} }

View File

@@ -1,8 +1,13 @@
namespace PS.IPAM; namespace PS.IPAM;
using System; using System;
/// <summary>
/// Represents the model types returned by the phpIPAM API.
/// </summary>
[Serializable] [Serializable]
public enum types { public enum ModelType
{
Address, Address,
Domain, Domain,
Section, Section,