DNS 2012 - first commit

This commit is contained in:
Konstantin 2013-11-28 20:38:38 +01:00
parent 872c8a675a
commit c13e350aa4
9 changed files with 1109 additions and 0 deletions

View file

@ -0,0 +1,287 @@
using System;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Net;
using WebsitePanel.Server.Utils;
namespace WebsitePanel.Providers.DNS
{
/// <summary>This class wraps MS DNS server PowerShell commands used by the WebsitePanel.</summary>
internal static class DnsCommands
{
/// <summary>Add parameter to PS command</summary>
/// <param name="cmd">command</param>
/// <param name="name">Parameter name</param>
/// <param name="value">Parameter value</param>
/// <returns>Same command</returns>
private static Command addParam( this Command cmd, string name, object value )
{
cmd.Parameters.Add( name, value );
return cmd;
}
/// <summary>Add parameter without value to the PS command</summary>
/// <param name="cmd">command</param>
/// <param name="name">Parameter name</param>
/// <returns>Same command</returns>
private static Command addParam( this Command cmd, string name )
{
cmd.Parameters.Add( name );
return cmd;
}
/// <summary>Create "Where-Object -Property ... -eq -Value ..." command</summary>
/// <param name="property"></param>
/// <param name="value"></param>
/// <returns></returns>
private static Command where( string property, object value )
{
return new Command( "Where-Object" )
.addParam( "Property", property )
.addParam( "eq" )
.addParam( "Value", value );
}
/// <summary>Test-DnsServer -IPAddress 127.0.0.1</summary>
/// <param name="ps">PowerShell host to use</param>
/// <returns>true if localhost is an MS DNS server</returns>
public static bool Test_DnsServer( this PowerShellHelper ps )
{
if( null == ps )
throw new ArgumentNullException( "ps" );
var cmd = new Command( "Test-DnsServer" )
.addParam( "IPAddress", IPAddress.Loopback );
PSObject res = ps.RunPipeline( cmd ).FirstOrDefault();
if( null == res || null == res.Properties )
return false;
PSPropertyInfo p = res.Properties[ "Result" ];
if( null == p || null == p.Value )
return false;
return p.Value.ToString() == "Success";
}
#region Zones
/// <summary>Get-DnsServerZone | Select-Object -Property ZoneName</summary>
/// <remarks>Only primary DNS zones are returned</remarks>
/// <returns>Array of zone names</returns>
public static string[] Get_DnsServerZone_Names( this PowerShellHelper ps )
{
var allZones = ps.RunPipeline( new Command( "Get-DnsServerZone" ),
where( "IsAutoCreated", false ) );
string[] res = allZones
.Select( pso => new
{
name = (string)pso.Properties[ "ZoneName" ].Value,
type = (string)pso.Properties[ "ZoneType" ].Value
} )
.Where( obj => obj.type == "Primary" )
.Select( obj => obj.name )
.ToArray();
Log.WriteInfo( "Get_DnsServerZone_Names: {{{0}}}", String.Join( ", ", res ) );
return res;
}
/// <summary>Returns true if the specified zone exists.</summary>
/// <remarks>The PS pipeline being run: Get-DnsServerZone | Where-Object -Property ZoneName -eq -Value "name"</remarks>
/// <param name="ps"></param>
/// <param name="name"></param>
/// <returns></returns>
public static bool ZoneExists( this PowerShellHelper ps, string name )
{
Log.WriteStart( "ZoneExists {0}", name );
bool res = ps.RunPipeline( new Command( "Get-DnsServerZone" ),
where( "ZoneName", name ) )
.Any();
Log.WriteEnd( "ZoneExists: {0}", res );
return res;
}
/* public enum eReplicationScope: byte
{
Custom, Domain, Forest, Legacy
} */
/// <summary></summary>
/// <param name="ps"></param>
/// <param name="zoneName"></param>
/// <param name="replicationScope">Specifies a partition on which to store an Active Directory-integrated zone.</param>
/// <returns></returns>
public static void Add_DnsServerPrimaryZone( this PowerShellHelper ps, string zoneName, string[] secondaryServers )
{
Log.WriteStart( "Add_DnsServerPrimaryZone {0} {{{1}}}", zoneName, String.Join( ", ", secondaryServers ) );
// Add-DnsServerPrimaryZone -Name zzz.com -ZoneFile zzz.com.dns
var cmd = new Command( "Add-DnsServerPrimaryZone" );
cmd.addParam( "Name", zoneName );
cmd.addParam( "ZoneFile", zoneName + ".dns" );
ps.RunPipeline( cmd );
// Set-DnsServerPrimaryZone -Name zzz.com -SecureSecondaries ... -Notify ... Servers ..
cmd = new Command( "Set-DnsServerPrimaryZone" );
cmd.addParam( "Name", zoneName );
if( secondaryServers == null || secondaryServers.Length == 0 )
{
// transfers are not allowed
// inParams2[ "SecureSecondaries" ] = 3;
// inParams2[ "Notify" ] = 0;
cmd.addParam( "SecureSecondaries", "NoTransfer" );
cmd.addParam( "Notify", "NoNotify" );
}
else if( secondaryServers.Length == 1 && secondaryServers[ 0 ] == "*" )
{
// allowed transfer from all servers
// inParams2[ "SecureSecondaries" ] = 0;
// inParams2[ "Notify" ] = 1;
cmd.addParam( "SecureSecondaries", "TransferAnyServer" );
cmd.addParam( "Notify", "Notify" );
}
else
{
// allowed transfer from specified servers
// inParams2[ "SecureSecondaries" ] = 2;
// inParams2[ "SecondaryServers" ] = secondaryServers;
// inParams2[ "NotifyServers" ] = secondaryServers;
// inParams2[ "Notify" ] = 2;
cmd.addParam( "SecureSecondaries", "TransferToSecureServers" );
cmd.addParam( "Notify", "NotifyServers" );
cmd.addParam( "SecondaryServers", secondaryServers );
cmd.addParam( "NotifyServers", secondaryServers );
}
ps.RunPipeline( cmd );
Log.WriteEnd( "Add_DnsServerPrimaryZone" );
}
public static void Add_DnsServerSecondaryZone( this PowerShellHelper ps, string zoneName, string[] masterServers )
{
// Add-DnsServerSecondaryZone -Name zzz.com -ZoneFile zzz.com.dns
var cmd = new Command( "Add-DnsServerSecondaryZone" );
cmd.addParam( "Name", zoneName );
cmd.addParam( "ZoneFile", zoneName + ".dns" );
ps.RunPipeline( cmd );
// Set-DnsServerSecondaryZone -Name zzz.com -MasterServers ...
cmd = new Command( "Set-DnsServerSecondaryZone" );
cmd.addParam( "Name", zoneName );
cmd.addParam( "MasterServers", masterServers );
ps.RunPipeline( cmd );
}
public static void Remove_DnsServerZone( this PowerShellHelper ps, string zoneName )
{
var cmd = new Command( "Remove-DnsServerZone" );
cmd.addParam( "Name", zoneName );
cmd.addParam( "Force" );
ps.RunPipeline( cmd );
}
#endregion
/// <summary>Get all records, except the SOA</summary>
/// <param name="ps"></param>
/// <param name="zoneName">Name of the zone</param>
/// <returns>Array of records</returns>
public static DnsRecord[] GetZoneRecords( this PowerShellHelper ps, string zoneName )
{
// Get-DnsServerResourceRecord -ZoneName xxxx.com
var allRecords = ps.RunPipeline( new Command( "Get-DnsServerResourceRecord" ).addParam( "ZoneName", zoneName ) );
return allRecords.Select( o => o.asDnsRecord( zoneName ) )
.Where( r => null != r )
.Where( r => r.RecordType != DnsRecordType.SOA )
// .Where( r => !( r.RecordName == "@" && DnsRecordType.NS == r.RecordType ) )
.ToArray();
}
#region Records add / remove
public static void Add_DnsServerResourceRecordA( this PowerShellHelper ps, string zoneName, string Name, string address )
{
var cmd = new Command( "Add-DnsServerResourceRecordA" );
cmd.addParam( "ZoneName", zoneName );
cmd.addParam( "Name", Name );
cmd.addParam( "IPv4Address", address );
ps.RunPipeline( cmd );
}
public static void Add_DnsServerResourceRecordAAAA( this PowerShellHelper ps, string zoneName, string Name, string address )
{
var cmd = new Command( "Add-DnsServerResourceRecordAAAA" );
cmd.addParam( "ZoneName", zoneName );
cmd.addParam( "Name", Name );
cmd.addParam( "IPv6Address", address );
ps.RunPipeline( cmd );
}
public static void Add_DnsServerResourceRecordCName( this PowerShellHelper ps, string zoneName, string Name, string alias )
{
var cmd = new Command( "Add-DnsServerResourceRecordCName" );
cmd.addParam( "ZoneName", zoneName );
cmd.addParam( "Name", Name );
cmd.addParam( "HostNameAlias", alias );
ps.RunPipeline( cmd );
}
public static void Add_DnsServerResourceRecordMX( this PowerShellHelper ps, string zoneName, string Name, string mx, UInt16 pref )
{
var cmd = new Command( "Add-DnsServerResourceRecordMX" );
cmd.addParam( "ZoneName", zoneName );
cmd.addParam( "Name", Name );
cmd.addParam( "MailExchange", mx );
cmd.addParam( "Preference", pref );
ps.RunPipeline( cmd );
}
public static void Add_DnsServerResourceRecordNS( this PowerShellHelper ps, string zoneName, string Name, string NameServer )
{
var cmd = new Command( "Add-DnsServerResourceRecord" );
cmd.addParam( "ZoneName", zoneName );
cmd.addParam( "Name", Name );
cmd.addParam( "NS" );
cmd.addParam( "NameServer", NameServer );
ps.RunPipeline( cmd );
}
public static void Add_DnsServerResourceRecordTXT( this PowerShellHelper ps, string zoneName, string Name, string txt )
{
var cmd = new Command( "Add-DnsServerResourceRecord" );
cmd.addParam( "ZoneName", zoneName );
cmd.addParam( "Name", Name );
cmd.addParam( "Txt" );
cmd.addParam( "DescriptiveText", txt );
ps.RunPipeline( cmd );
}
public static void Add_DnsServerResourceRecordSRV( this PowerShellHelper ps, string zoneName, string Name, string DomainName, UInt16 Port, UInt16 Priority, UInt16 Weight )
{
var cmd = new Command( "Add-DnsServerResourceRecord" );
cmd.addParam( "ZoneName", zoneName );
cmd.addParam( "Name", Name );
cmd.addParam( "Srv" );
cmd.addParam( "DomainName", DomainName );
cmd.addParam( "Port", Port );
cmd.addParam( "Priority", Priority );
cmd.addParam( "Weight", Weight );
ps.RunPipeline( cmd );
}
public static void Remove_DnsServerResourceRecord( this PowerShellHelper ps, string zoneName, string Name, string type )
{
// Remove-DnsServerResourceRecord -ZoneName xxxx.com -Name "@" -RRType Soa -Force
var cmd = new Command( "Remove-DnsServerResourceRecord" );
cmd.addParam( "ZoneName", zoneName );
cmd.addParam( "Name", Name );
cmd.addParam( "RRType", type );
cmd.addParam( "Force" );
ps.RunPipeline( cmd );
}
#endregion
}
}

View file

@ -0,0 +1,424 @@
// Copyright (c) 2012, Outercurve Foundation.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// A lot of modifications made since 2012..
using System;
using System.Management;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using WebsitePanel.Server.Utils;
using WebsitePanel.Providers.Utils;
namespace WebsitePanel.Providers.DNS
{
public class MsDNS: HostingServiceProviderBase, IDnsServer
{
protected int ExpireLimit
{
get { return ProviderSettings.GetInt( "ExpireLimit" ); }
}
protected int MinimumTTL
{
get { return ProviderSettings.GetInt( "MinimumTTL" ); }
}
protected int RefreshInterval
{
get { return ProviderSettings.GetInt( "RefreshInterval" ); }
}
protected int RetryDelay
{
get { return ProviderSettings.GetInt( "RetryDelay" ); }
}
protected bool AdMode
{
get { return ProviderSettings.GetBool( "AdMode" ); }
}
private PowerShellHelper ps = null;
private WmiHelper wmi = null; //< We still need WMI because PowerShell doesn't support SOA updates.
private bool bulkRecords;
public MsDNS()
{
// Create PowerShell helper
ps = new PowerShellHelper();
if( !this.IsInstalled() )
return;
// Create WMI helper
wmi = new WmiHelper( "root\\MicrosoftDNS" );
}
#region Zones
public virtual string[] GetZones()
{
return ps.Get_DnsServerZone_Names();
}
public virtual bool ZoneExists( string zoneName )
{
return ps.ZoneExists( zoneName );
}
public virtual DnsRecord[] GetZoneRecords( string zoneName )
{
return ps.GetZoneRecords( zoneName );
}
public virtual void AddPrimaryZone( string zoneName, string[] secondaryServers )
{
ps.Add_DnsServerPrimaryZone( zoneName, secondaryServers );
// delete orphan NS records
DeleteOrphanNsRecords( zoneName );
}
public virtual void AddSecondaryZone( string zoneName, string[] masterServers )
{
ps.Add_DnsServerSecondaryZone( zoneName, masterServers );
// delete orphan NS records
DeleteOrphanNsRecords( zoneName );
}
public virtual void DeleteZone( string zoneName )
{
try
{
ps.Remove_DnsServerZone( zoneName );
}
catch( Exception ex )
{
Log.WriteError( ex );
}
}
public virtual void AddZoneRecord( string zoneName, DnsRecord record )
{
try
{
string name = record.RecordName;
if( String.IsNullOrEmpty( name ) )
name = ".";
if( record.RecordType == DnsRecordType.A )
ps.Add_DnsServerResourceRecordA( zoneName, name, record.RecordData );
else if( record.RecordType == DnsRecordType.AAAA )
ps.Add_DnsServerResourceRecordAAAA( zoneName, name, record.RecordData );
else if( record.RecordType == DnsRecordType.CNAME )
ps.Add_DnsServerResourceRecordCName( zoneName, name, record.RecordData );
else if( record.RecordType == DnsRecordType.MX )
ps.Add_DnsServerResourceRecordMX( zoneName, name, record.RecordData, (ushort)record.MxPriority );
else if( record.RecordType == DnsRecordType.NS )
ps.Add_DnsServerResourceRecordNS( zoneName, name, record.RecordData );
else if( record.RecordType == DnsRecordType.TXT )
ps.Add_DnsServerResourceRecordTXT( zoneName, name, record.RecordData );
else if( record.RecordType == DnsRecordType.SRV )
ps.Add_DnsServerResourceRecordSRV( zoneName, name, record.RecordData, (ushort)record.SrvPort, (ushort)record.SrvPriority, (ushort)record.SrvWeight );
else
throw new Exception( "Unknown record type" );
}
catch( Exception ex )
{
// log exception
Log.WriteError( ex );
}
}
public virtual void AddZoneRecords( string zoneName, DnsRecord[] records )
{
bulkRecords = true;
try
{
foreach( DnsRecord record in records )
AddZoneRecord( zoneName, record );
}
finally
{
bulkRecords = false;
}
UpdateSoaRecord( zoneName );
}
public virtual void DeleteZoneRecord( string zoneName, DnsRecord record )
{
try
{
string rrType;
if( !RecordTypes.rrTypeFromRecord.TryGetValue( record.RecordType, out rrType ) )
throw new Exception( "Unknown record type" );
ps.Remove_DnsServerResourceRecord( zoneName, record.RecordName, rrType );
}
catch( Exception ex )
{
// log exception
Log.WriteError( ex );
}
}
public virtual void DeleteZoneRecords( string zoneName, DnsRecord[] records )
{
foreach( DnsRecord record in records )
DeleteZoneRecord( zoneName, record );
}
public void AddZoneRecord( string zoneName, string recordText )
{
try
{
Log.WriteStart( string.Format( "Adding MS DNS Server zone '{0}' record '{1}'", zoneName, recordText ) );
AddDnsRecord( zoneName, recordText );
Log.WriteEnd( "Added MS DNS Server zone record" );
}
catch( Exception ex )
{
Log.WriteError( ex );
throw;
}
}
#endregion
#region SOA Record
public virtual void UpdateSoaRecord( string zoneName, string host, string primaryNsServer, string primaryPerson )
{
host = CorrectHostName( zoneName, host );
// delete record if exists
DeleteSoaRecord( zoneName );
// format record data
string recordText = GetSoaRecordText( host, primaryNsServer, primaryPerson );
// add record
AddDnsRecord( zoneName, recordText );
// update SOA record
UpdateSoaRecord( zoneName );
}
private void DeleteSoaRecord( string zoneName )
{
// TODO: find a PowerShell replacement
string query = String.Format( "SELECT * FROM MicrosoftDNS_SOAType " +
"WHERE OwnerName = '{0}'",
zoneName );
using( ManagementObjectCollection objRRs = wmi.ExecuteQuery( query ) )
{
foreach( ManagementObject objRR in objRRs ) using( objRR )
objRR.Delete();
}
// This doesn't work: no errors in PS, but the record stays in the DNS
/* try
{
ps.Remove_DnsServerResourceRecord( zoneName, "@", "Soa" );
}
catch( System.Exception ex )
{
Log.WriteWarning( "{0}", ex.Message );
} */
}
private string GetSoaRecordText( string host, string primaryNsServer, string primaryPerson )
{
return String.Format( "{0} IN SOA {1} {2} 1 900 600 86400 3600", host, primaryNsServer, primaryPerson );
}
private static string RemoveTrailingDot( string str )
{
return ( str.EndsWith( "." ) ) ? str.Substring( 0, str.Length - 1 ) : str;
}
private void UpdateSoaRecord( string zoneName )
{
if( bulkRecords )
return;
// TODO: find a PowerShell replacement
// get existing SOA record in order to read serial number
try
{
ManagementObject objSoa = wmi.GetWmiObject( "MicrosoftDNS_SOAType", "ContainerName = '{0}'", RemoveTrailingDot( zoneName ) );
if( objSoa != null )
{
if( objSoa.Properties[ "OwnerName" ].Value.Equals( zoneName ) )
{
string primaryServer = (string)objSoa.Properties[ "PrimaryServer" ].Value;
string responsibleParty = (string)objSoa.Properties[ "ResponsibleParty" ].Value;
UInt32 serialNumber = (UInt32)objSoa.Properties[ "SerialNumber" ].Value;
// update record's serial number
string sn = serialNumber.ToString();
string todayDate = DateTime.Now.ToString( "yyyyMMdd" );
if( sn.Length < 10 || !sn.StartsWith( todayDate ) )
{
// build a new serial number
sn = todayDate + "01";
serialNumber = UInt32.Parse( sn );
}
else
{
// just increment serial number
serialNumber += 1;
}
// update SOA record
using( ManagementBaseObject methodParams = objSoa.GetMethodParameters( "Modify" ) )
{
methodParams[ "ResponsibleParty" ] = responsibleParty;
methodParams[ "PrimaryServer" ] = primaryServer;
methodParams[ "SerialNumber" ] = serialNumber;
methodParams[ "ExpireLimit" ] = ExpireLimit;
methodParams[ "MinimumTTL" ] = MinimumTTL;
methodParams[ "TTL" ] = MinimumTTL;
methodParams[ "RefreshInterval" ] = RefreshInterval;
methodParams[ "RetryDelay" ] = RetryDelay;
ManagementBaseObject outParams = objSoa.InvokeMethod( "Modify", methodParams, null );
}
//
objSoa.Dispose();
}
}
}
catch( Exception ex )
{
Log.WriteError( ex );
}
}
#endregion
private void DeleteOrphanNsRecords( string zoneName )
{
// TODO: find a PowerShell replacement
string machineName = System.Net.Dns.GetHostEntry( "LocalHost" ).HostName.ToLower();
string computerName = Environment.MachineName.ToLower();
using( ManagementObjectCollection objRRs = wmi.ExecuteQuery( String.Format( "SELECT * FROM MicrosoftDNS_NSType WHERE DomainName = '{0}'", zoneName ) ) )
{
foreach( ManagementObject objRR in objRRs )
{
using( objRR )
{
string ns = ( (string)objRR.Properties[ "NSHost" ].Value ).ToLower();
if( ns.StartsWith( machineName ) || ns.StartsWith( computerName ) )
objRR.Delete();
}
}
}
}
#region private helper methods
private string GetDnsServerName()
{
// TODO: find a PowerShell replacement
using( ManagementObject objServer = wmi.GetObject( "MicrosoftDNS_Server.Name=\".\"" ) )
{
return (string)objServer.Properties[ "Name" ].Value;
}
}
private string AddDnsRecord( string zoneName, string recordText )
{
// get the name of the server
string serverName = GetDnsServerName();
// TODO: find a PowerShell replacement
// add record
using( ManagementClass clsRR = wmi.GetClass( "MicrosoftDNS_ResourceRecord" ) )
{
object[] prms = new object[] { serverName, zoneName, recordText, null };
clsRR.InvokeMethod( "CreateInstanceFromTextRepresentation", prms );
return (string)prms[ 3 ];
}
}
private string CorrectHostName( string zoneName, string host )
{
// if host is empty or null
if( host == null || host == "" )
return zoneName;
// if there are not dot at all
else if( host.IndexOf( "." ) == -1 )
return host + "." + zoneName;
// if only one dot at the end
else if( host[ host.Length - 1 ] == '.' && host.IndexOf( "." ) == ( host.Length - 1 ) )
return host + zoneName;
// other cases
else
return host;
}
#endregion
public override void DeleteServiceItems( ServiceProviderItem[] items )
{
foreach( ServiceProviderItem item in items )
{
if( item is DnsZone )
{
try
{
// delete DNS zone
DeleteZone( item.Name );
}
catch( Exception ex )
{
Log.WriteError( String.Format( "Error deleting '{0}' MS DNS zone", item.Name ), ex );
}
}
}
}
public override bool IsInstalled()
{
return ps.Test_DnsServer();
}
}
}

View file

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using WebsitePanel.Server.Utils;
namespace WebsitePanel.Providers.DNS
{
/// <summary>This class is a generic helper hosting the PowerShell runtime.</summary>
/// <remarks>It's probably a good idea to move to some utility module.</remarks>
public class PowerShellHelper: IDisposable
{
private static InitialSessionState s_session = null;
static PowerShellHelper()
{
s_session = InitialSessionState.CreateDefault();
// s_session.ImportPSModule( new string[] { "FileServerResourceManager" } );
}
public PowerShellHelper()
{
Log.WriteStart( "PowerShellHelper::ctor" );
Runspace rs = RunspaceFactory.CreateRunspace( s_session );
rs.Open();
// rs.SessionStateProxy.SetVariable( "ConfirmPreference", "none" );
this.runSpace = rs;
Log.WriteEnd( "PowerShellHelper::ctor" );
}
public void Dispose()
{
try
{
if( this.runSpace == null )
return;
if( this.runSpace.RunspaceStateInfo.State == RunspaceState.Opened )
this.runSpace.Close();
this.runSpace = null;
}
catch( Exception ex )
{
Log.WriteError( "Runspace error", ex );
}
}
public Runspace runSpace { get; private set; }
public Collection<PSObject> RunPipeline( params Command[] pipelineCommands )
{
Log.WriteStart( "ExecuteShellCommand" );
List<object> errorList = new List<object>();
Collection<PSObject> results = null;
using( Pipeline pipeLine = runSpace.CreatePipeline() )
{
// Add the command
foreach( var cmd in pipelineCommands )
pipeLine.Commands.Add( cmd );
// Execute the pipeline and save the objects returned.
results = pipeLine.Invoke();
// Only non-terminating errors are delivered here.
// Terminating errors raise exceptions instead.
if( null != pipeLine.Error && pipeLine.Error.Count > 0 )
{
foreach( object item in pipeLine.Error.ReadToEnd() )
{
errorList.Add( item );
string errorMessage = string.Format( "Invoke error: {0}", item );
Log.WriteWarning( errorMessage );
}
}
}
// errors = errorList.ToArray();
Log.WriteEnd( "ExecuteShellCommand" );
return results;
}
}
}

View file

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WebsitePanel.Providers.DNS.MsDNS2012")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WebsitePanel.Providers.DNS.MsDNS2012")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f2a902f2-5654-4e67-8c5e-4d2fdf6de873")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,147 @@
using System;
using System.Linq;
using System.Management.Automation;
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Generic;
using WebsitePanel.Server.Utils;
namespace WebsitePanel.Providers.DNS
{
/// <summary>Copy fields from CimInstance#DnsServerResourceRecord into DnsRecord</summary>
/// <remarks>It's also possible to access native CIM object, and use Mgmtclassgen.exe for that.</remarks>
internal static class RecordConverter
{
private static string RemoveTrailingDot( string str )
{
if( !str.EndsWith( "." ) )
return str;
return str.Substring( 0, str.Length - 1 );
}
private static string CorrectHost( string zoneName, string host )
{
if( host.ToLower() == zoneName.ToLower() )
return "";
if( host.ToLower().EndsWith( "." + zoneName.ToLower() ) )
return host.Substring( 0, ( host.Length - zoneName.Length - 1 ) );
return host;
}
public static DnsRecord asDnsRecord( this PSObject obj, string zoneName )
{
// Here's what comes from Server 2012 in the TypeNames:
// "Microsoft.Management.Infrastructure.CimInstance#root/Microsoft/Windows/DNS/DnsServerResourceRecord"
// "Microsoft.Management.Infrastructure.CimInstance#ROOT/Microsoft/Windows/DNS/DnsDomain"
// "Microsoft.Management.Infrastructure.CimInstance#DnsServerResourceRecord"
// "Microsoft.Management.Infrastructure.CimInstance#DnsDomain"
// "Microsoft.Management.Infrastructure.CimInstance"
// "System.Object" string
if( !obj.TypeNames.Contains( "Microsoft.Management.Infrastructure.CimInstance#DnsServerResourceRecord" ) )
{
Log.WriteWarning( "asDnsRecord: wrong object type {0}", obj.TypeNames.FirstOrDefault() );
return null;
}
string strRT = (string)obj.Properties[ "RecordType" ].Value;
DnsRecordType tp;
if( !RecordTypes.recordFromString.TryGetValue( strRT, out tp ) )
return null;
/*// Debug code below:
obj.dumpProperties();
CimInstance rd = (CimInstance)obj.Properties[ "RecordData" ].Value;
rd.dumpProperties(); //*/
CimKeyedCollection<CimProperty> data = ( (CimInstance)obj.Properties[ "RecordData" ].Value ).CimInstanceProperties;
string host = CorrectHost( zoneName, (string)obj.Properties[ "HostName" ].Value );
switch( tp )
{
// The compiler should create a Dictionary<> from dis switch
case DnsRecordType.A:
{
return new DnsRecord()
{
RecordType = tp,
RecordName = host,
RecordData = data[ "IPv4Address" ].Value as string,
};
}
case DnsRecordType.AAAA:
{
return new DnsRecord()
{
RecordType = tp,
RecordName = host,
RecordData = data[ "IPv6Address" ].Value as string,
};
}
case DnsRecordType.CNAME:
{
return new DnsRecord()
{
RecordType = tp,
RecordName = host,
RecordData = RemoveTrailingDot( data[ "HostNameAlias" ].Value as string ),
};
}
case DnsRecordType.MX:
{
return new DnsRecord()
{
RecordType = tp,
RecordName = host,
RecordData = RemoveTrailingDot( data[ "MailExchange" ].Value as string ),
MxPriority = (UInt16)data[ "Preference" ].Value,
};
}
case DnsRecordType.NS:
{
return new DnsRecord()
{
RecordType = tp,
RecordName = host,
RecordData = RemoveTrailingDot( data[ "NameServer" ].Value as string ),
};
}
case DnsRecordType.TXT:
{
return new DnsRecord()
{
RecordType = tp,
RecordName = host,
RecordData = data[ "DescriptiveText" ].Value as string,
};
}
case DnsRecordType.SOA:
{
string PrimaryServer = data[ "PrimaryServer" ].Value as string;
string ResponsiblePerson = data[ "ResponsiblePerson" ].Value as string;
UInt32? sn = (UInt32?)data[ "SerialNumber" ].Value;
return new DnsSOARecord()
{
RecordType = tp,
RecordName = host,
PrimaryNsServer = PrimaryServer,
PrimaryPerson = ResponsiblePerson,
SerialNumber = ( sn.HasValue ) ? sn.Value.ToString() : null,
};
}
case DnsRecordType.SRV:
{
return new DnsRecord()
{
RecordType = tp,
RecordName = host,
RecordData = RemoveTrailingDot( data[ "DomainName" ].Value as string ),
SrvPriority = (UInt16)data[ "Priority" ].Value,
SrvWeight = (UInt16)data[ "Weight" ].Value,
SrvPort = (UInt16)data[ "Port" ].Value,
};
}
}
return null;
}
}
}

View file

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace WebsitePanel.Providers.DNS
{
/// <summary>This static class holds 2 lookup tables, from/to DnsRecordType enum</summary>
internal static class RecordTypes
{
static readonly Dictionary<string, DnsRecordType> s_lookup;
static readonly Dictionary<DnsRecordType, string> s_lookupInv;
static RecordTypes()
{
s_lookup = new Dictionary<string, DnsRecordType>()
{
{ "A", DnsRecordType.A },
{ "AAAA", DnsRecordType.AAAA },
{ "NS", DnsRecordType.NS },
{ "MX", DnsRecordType.MX },
{ "CNAME", DnsRecordType.CNAME },
{ "SOA", DnsRecordType.SOA },
{ "TXT", DnsRecordType.TXT },
{ "SRV", DnsRecordType.SRV },
};
TextInfo ti = new CultureInfo( "en-US", false ).TextInfo;
s_lookupInv = s_lookup
.ToDictionary( kvp => kvp.Value, kvp => ti.ToTitleCase( kvp.Key ) );
}
/// <summary>The dictionary that maps string record types to DnsRecordType enum</summary>
public static Dictionary<string, DnsRecordType> recordFromString { get { return s_lookup; } }
/// <summary>the dictionary that maps DnsRecordType enum to strings, suitable for PowerShell </summary>
public static Dictionary<DnsRecordType, string> rrTypeFromRecord { get { return s_lookupInv; } }
}
}

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WebsitePanel.Providers.DNS.MsDNS2012</RootNamespace>
<AssemblyName>WebsitePanel.Providers.DNS.MsDNS2012</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Management.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Lib\Microsoft.Management.Infrastructure.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Management" />
<Reference Include="System.Management.Automation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\Lib\System.Management.Automation.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DnsCommands.cs" />
<Compile Include="MsDNS.cs" />
<Compile Include="PowerShellHelper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RecordConverter.cs" />
<Compile Include="RecordTypes.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WebsitePanel.Providers.Base\WebsitePanel.Providers.Base.csproj">
<Project>{684c932a-6c75-46ac-a327-f3689d89eb42}</Project>
<Name>WebsitePanel.Providers.Base</Name>
</ProjectReference>
<ProjectReference Include="..\WebsitePanel.Server.Utils\WebsitePanel.Server.Utils.csproj">
<Project>{e91e52f3-9555-4d00-b577-2b1dbdd87ca7}</Project>
<Name>WebsitePanel.Server.Utils</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -142,6 +142,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.Host
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.Web.WebDav", "WebsitePanel.Providers.Web.WebDav\WebsitePanel.Providers.Web.WebDav.csproj", "{CE2DF3D7-D6FF-48FA-B2EA-7B836FCBF698}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.DNS.MsDNS2012", "WebsitePanel.Providers.DNS.MsDNS2012\WebsitePanel.Providers.DNS.MsDNS2012.csproj", "{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}"
ProjectSection(ProjectDependencies) = postProject
{684C932A-6C75-46AC-A327-F3689D89EB42} = {684C932A-6C75-46AC-A327-F3689D89EB42}
{E91E52F3-9555-4D00-B577-2B1DBDD87CA7} = {E91E52F3-9555-4D00-B577-2B1DBDD87CA7}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -732,6 +738,16 @@ Global
{CE2DF3D7-D6FF-48FA-B2EA-7B836FCBF698}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{CE2DF3D7-D6FF-48FA-B2EA-7B836FCBF698}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{CE2DF3D7-D6FF-48FA-B2EA-7B836FCBF698}.Release|x86.ActiveCfg = Release|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Debug|x86.ActiveCfg = Debug|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Release|Any CPU.Build.0 = Release|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{FA0FB0BA-5A39-4F4E-8EC2-B806B58B74D4}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE