├── .gitignore
├── LICENSE
├── RDCManager
├── InitializeModule.ps1
├── RdcManager.psd1
├── RdcManager.psm1
├── img
│ ├── ZMRivZa5sA.png
│ └── xIkQfDVql2.png
├── private
│ ├── ADSI
│ │ ├── GetAdsiComputer.ps1
│ │ ├── GetAdsiObject.ps1
│ │ ├── GetAdsiOrganizationalUnit.ps1
│ │ ├── GetAdsiRootDSE.ps1
│ │ └── NewDirectoryEntry.ps1
│ └── CommandAdapter
│ │ ├── GetADComputer.ps1
│ │ ├── GetADObject.ps1
│ │ └── GetADOrganizationalUnit.ps1
└── public
│ ├── Configuration
│ ├── Get-RdcConfiguration.ps1
│ └── Set-RdcConfiguration.ps1
│ └── DSL
│ ├── ADConfiguration.ps1
│ ├── RdcADComputer.ps1
│ ├── RdcADGroup.ps1
│ ├── RdcComputer.ps1
│ ├── RdcConfiguration.ps1
│ ├── RdcDocument.ps1
│ ├── RdcGroup.ps1
│ ├── RdcLogonCredential.ps1
│ └── RdcRemoteDesktopSetting.ps1
├── build.ps1
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | out
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Brett Miller
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/RDCManager/InitializeModule.ps1:
--------------------------------------------------------------------------------
1 | Add-Type -AssemblyName System.Xml.Linq
2 |
3 | function InitializeModule {
4 | Set-RdcConfiguration -Reset
5 | }
6 |
--------------------------------------------------------------------------------
/RDCManager/RdcManager.psd1:
--------------------------------------------------------------------------------
1 | #
2 | # Module manifest for module 'RDCManager'
3 | #
4 | # Generated by: Brett Miller & Chris Dent
5 | #
6 | # Generated on: 25/01/2019
7 | #
8 |
9 | @{
10 |
11 | # Script module or binary module file associated with this manifest.
12 | RootModule = 'RDCManager.psm1'
13 |
14 | # Version number of this module.
15 | ModuleVersion = '2.1.3'
16 |
17 | # Supported PSEditions
18 | CompatiblePSEditions = 'Desktop', 'Core'
19 |
20 | # ID used to uniquely identify this module
21 | GUID = '22a5df6b-7620-47de-8103-abc1869af639'
22 |
23 | # Author of this module
24 | Author = 'Brett Miller & Chris Dent'
25 |
26 | # Company or vendor of this module
27 | CompanyName = 'None'
28 |
29 | # Copyright statement for this module
30 | Copyright = '(c) 2019 Brett Miller & Chris Dent. All rights reserved.'
31 |
32 | # Description of the functionality provided by this module
33 | Description = 'A DSL used to generate Remote Desktop Connection Manager files'
34 |
35 | # Minimum version of the Windows PowerShell engine required by this module
36 | PowerShellVersion = '5.1'
37 |
38 | # Name of the Windows PowerShell host required by this module
39 | # PowerShellHostName = ''
40 |
41 | # Minimum version of the Windows PowerShell host required by this module
42 | # PowerShellHostVersion = ''
43 |
44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45 | # DotNetFrameworkVersion = ''
46 |
47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48 | # CLRVersion = ''
49 |
50 | # Processor architecture (None, X86, Amd64) required by this module
51 | # ProcessorArchitecture = ''
52 |
53 | # Modules that must be imported into the global environment prior to importing this module
54 | # RequiredModules = @()
55 |
56 | # Assemblies that must be loaded prior to importing this module
57 | # RequiredAssemblies = @()
58 |
59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module.
60 | # ScriptsToProcess = @()
61 |
62 | # Type files (.ps1xml) to be loaded when importing this module
63 | # TypesToProcess = @()
64 |
65 | # Format files (.ps1xml) to be loaded when importing this module
66 | # FormatsToProcess = @()
67 |
68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69 | # NestedModules = @()
70 |
71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72 | FunctionsToExport = @(
73 | 'Get-RdcConfiguration',
74 | 'Set-RdcConfiguration',
75 | 'ADConfiguration',
76 | 'RdcADComputer',
77 | 'RdcADGroup',
78 | 'RdcComputer',
79 | 'RdcConfiguration',
80 | 'RdcDocument',
81 | 'RdcGroup',
82 | 'RdcLogonCredential',
83 | 'RdcRemoteDesktopSetting'
84 | )
85 |
86 |
87 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
88 | CmdletsToExport = @()
89 |
90 | # Variables to export from this module
91 | VariablesToExport = @()
92 |
93 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
94 | AliasesToExport = @()
95 |
96 | # DSC resources to export from this module
97 | # DscResourcesToExport = @()
98 |
99 | # List of all modules packaged with this module
100 | # ModuleList = @()
101 |
102 | # List of all files packaged with this module
103 | # FileList = @()
104 |
105 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
106 | PrivateData = @{
107 |
108 | PSData = @{
109 |
110 | # Tags applied to this module. These help with module discovery in online galleries.
111 | Tags = @('RDCMan', 'RDCManager', 'RemoteDesktop')
112 |
113 | # A URL to the license for this module.
114 | # LicenseUri = ''
115 |
116 | # A URL to the main website for this project.
117 | ProjectUri = 'https://github.com/brettmillerb/RDCMan'
118 |
119 | # A URL to an icon representing this module.
120 | # IconUri = ''
121 |
122 | # ReleaseNotes of this module
123 | # ReleaseNotes = ''
124 |
125 | } # End of PSData hashtable
126 |
127 | } # End of PrivateData hashtable
128 |
129 | # HelpInfo URI of this module
130 | # HelpInfoURI = ''
131 |
132 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
133 | # DefaultCommandPrefix = ''
134 |
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/RDCManager/RdcManager.psm1:
--------------------------------------------------------------------------------
1 | # Development root module
2 |
3 | $private = @(
4 | 'ADSI\GetAdsiComputer'
5 | 'ADSI\GetAdsiObject'
6 | 'ADSI\GetAdsiOrganizationalUnit'
7 | 'ADSI\GetAdsiRootDSE'
8 | 'ADSI\NewDirectoryEntry'
9 | 'CommandAdapter\GetADComputer'
10 | 'CommandAdapter\GetADObject'
11 | 'CommandAdapter\GetADOrganizationalUnit'
12 | )
13 |
14 | foreach ($command in $private) {
15 | . ('{0}\private\{1}.ps1' -f $psscriptroot, $command)
16 |
17 | Split-Path $command -Leaf
18 | }
19 |
20 | $public = @(
21 | 'Configuration\Get-RdcConfiguration'
22 | 'Configuration\Set-RdcConfiguration'
23 | 'DSL\ADConfiguration'
24 | 'DSL\RdcADComputer'
25 | 'DSL\RdcADGroup'
26 | 'DSL\RdcComputer'
27 | 'DSL\RdcConfiguration'
28 | 'DSL\RdcDocument'
29 | 'DSL\RdcGroup'
30 | 'DSL\RdcLogonCredential'
31 | 'DSL\RdcRemoteDesktopSetting'
32 | )
33 |
34 | $functionsToExport = foreach ($command in $public) {
35 | . ('{0}\public\{1}.ps1' -f $psscriptroot, $command)
36 |
37 | Split-Path $command -Leaf
38 | }
39 |
40 | . ('{0}\InitializeModule.ps1' -f $psscriptroot)
41 | InitializeModule
42 |
43 | Export-ModuleMember -Function $functionsToExport
--------------------------------------------------------------------------------
/RDCManager/img/ZMRivZa5sA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brettmillerb/RDCMan/bc48b25acc5d6c9102ed177bcef4e3f9bc818482/RDCManager/img/ZMRivZa5sA.png
--------------------------------------------------------------------------------
/RDCManager/img/xIkQfDVql2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/brettmillerb/RDCMan/bc48b25acc5d6c9102ed177bcef4e3f9bc818482/RDCManager/img/xIkQfDVql2.png
--------------------------------------------------------------------------------
/RDCManager/private/ADSI/GetAdsiComputer.ps1:
--------------------------------------------------------------------------------
1 | function GetAdsiComputer {
2 | <#
3 | .SYNOPSIS
4 | Get an computer object using ADSI.
5 | .DESCRIPTION
6 | These basic ADSI commands allow the RdcMan document generator to be used without the MS AD module.
7 |
8 | Use of the internal commands is optional. If used, all filters must be written as LDAP filter.
9 | #>
10 |
11 | [CmdletBinding()]
12 | param (
13 | # A filter describing the computers units to find.
14 | [String]$Filter,
15 |
16 | # The search base for this search.
17 | [String]$SearchBase,
18 |
19 | # The search scope for the search operation.
20 | [System.DirectoryServices.SearchScope]$SearchScope,
21 |
22 | # Limit the number of results returned by a search. By default result set size is unlimited.
23 | [Int32]$ResultSetSize,
24 |
25 | # The server to use to execute the search.
26 | [String]$Server,
27 |
28 | # Credentials to use when connecting to the server.
29 | [PSCredential]$Credential
30 | )
31 |
32 | if ($Filter -eq '*' -or -not $Filter) {
33 | $psboundparameters['Filter'] = '(&(objectCategory=computer)(objectClass=computer))'
34 | } else {
35 | $psboundparameters['Filter'] = '(&(objectCategory=computer)(objectClass=computer){0})' -f $Filter
36 | }
37 |
38 | GetAdsiObject -Properties 'name', 'description', 'dnsHostName' @psboundparameters
39 | }
--------------------------------------------------------------------------------
/RDCManager/private/ADSI/GetAdsiObject.ps1:
--------------------------------------------------------------------------------
1 | function GetAdsiObject {
2 | <#
3 | .SYNOPSIS
4 | Get an arbitrary object using ADSI.
5 | .DESCRIPTION
6 | These basic ADSI commands allow the RdcMan document generator to be used without the MS AD module.
7 |
8 | Use of the internal commands is optional. If used, all filters must be written as LDAP filter.
9 | #>
10 |
11 | [CmdletBinding()]
12 | param (
13 | # A filter describing the computers units to find.
14 | [Parameter(Mandatory)]
15 | [String]$Filter,
16 |
17 | # A list of properties to retrieve
18 | [String[]]$Properties = 'distinguishedName',
19 |
20 | # The search base for this search.
21 | [String]$SearchBase,
22 |
23 | # The search scope for the search operation.
24 | [System.DirectoryServices.SearchScope]$SearchScope,
25 |
26 | # Limit the number of results returned by a search. By default result set size is unlimited.
27 | [Int32]$ResultSetSize,
28 |
29 | # The server to use to execute the search.
30 | [String]$Server,
31 |
32 | # Credentials to use when connecting to the server.
33 | [PSCredential]$Credential
34 | )
35 |
36 | $params = @{}
37 | if ($Server) { $params.Add('Server', $Server) }
38 | if ($Credential) { $params.Add('Credential', $Credential) }
39 |
40 | $params = @{}
41 | if ($Server) { $params.Add('Server', $Server) }
42 | if ($Credential) { $params.Add('Credential', $Credential) }
43 |
44 | if (-not $SearchBase) {
45 | $SearchBase = (GetAdsiRootDse @params).defaultNamingContext
46 | }
47 | $adsiSearchBase = NewDirectoryEntry -DistinguishedName $SearchBase @params
48 |
49 | $searcher = [ADSISearcher]@{
50 | Filter = $Filter
51 | SearchRoot = $adsiSearchBase
52 | SearchScope = $SearchScope
53 | PageSize = 1000
54 | }
55 | $searcher.PropertiesToLoad.AddRange($Properties)
56 |
57 | if ($ResultSetSize) {
58 | $searcher.SizeLimit = $ResultSetSize
59 | }
60 |
61 | Write-Debug 'SEARCHER:'
62 | Write-Debug (' Filter : {0}' -f $Filter)
63 | Write-Debug (' SearchBase : {0}' -f $SearchBase)
64 | Write-Debug (' SearchScope: {0}' -f $SearchScope)
65 |
66 | foreach ($searchResult in $searcher.FindAll()) {
67 | $objectProperties = @{}
68 | foreach ($property in $Properties) {
69 | $objectProperties.Add($property, $searchResult.Properties[$property][0])
70 | }
71 | [PSCustomObject]$objectProperties
72 | }
73 | }
--------------------------------------------------------------------------------
/RDCManager/private/ADSI/GetAdsiOrganizationalUnit.ps1:
--------------------------------------------------------------------------------
1 | function GetAdsiOrganizationalUnit {
2 | <#
3 | .SYNOPSIS
4 | Get an organization unit object using ADSI.
5 | .DESCRIPTION
6 | These basic ADSI commands allow the RdcMan document generator to be used without the MS AD module.
7 |
8 | Use of the internal commands is optional. If used, all filters must be written as LDAP filter.
9 | #>
10 |
11 | [CmdletBinding(DefaultParameterSetName = 'UsingFilter')]
12 | param (
13 | # A filter describing the organizational units to find.
14 | [Parameter(ParameterSetName = 'UsingFilter')]
15 | [String]$Filter,
16 |
17 | # Use identity instead of a filter to locate the OU.
18 | [Parameter(ParameterSetName = 'ByIdentity')]
19 | [String]$Identity,
20 |
21 | # The search base for this search.
22 | [String]$SearchBase,
23 |
24 | # The search scope for the search operation.
25 | [System.DirectoryServices.SearchScope]$SearchScope,
26 |
27 | # The server to use to execute the search.
28 | [String]$Server,
29 |
30 | # Credentials to use when connecting to the server.
31 | [PSCredential]$Credential
32 | )
33 |
34 | if ($Identity) {
35 | $psboundparameters['Filter'] = '(&(objectClass=organizationalUnit)(distinguishedName={0}))' -f $Identity
36 | $psboundparameters['SearchScope'] = 'Subtree'
37 | $null = $psboundparameters.Remove('Identity')
38 | } elseif ($Filter -eq '*' -or -not $Filter) {
39 | $psboundparameters['Filter'] = '(objectClass=organizationalUnit)'
40 | } else {
41 | $psboundparameters['Filter'] = '(&(objectClass=organizationalUnit){0})' -f $Filter
42 | }
43 |
44 | GetAdsiObject -Properties 'name', 'description', 'distinguishedName' @psboundparameters
45 | }
--------------------------------------------------------------------------------
/RDCManager/private/ADSI/GetAdsiRootDSE.ps1:
--------------------------------------------------------------------------------
1 | function GetAdsiRootDse {
2 | <#
3 | .SYNOPSIS
4 | Get a RootDSE node using ADSI.
5 | .DESCRIPTION
6 | These basic ADSI commands allow the RdcMan document generator to be used without the MS AD module.
7 |
8 | Use of the internal commands is optional. If used, all filters must be written as LDAP filter.
9 | #>
10 |
11 | [CmdletBinding()]
12 | param (
13 | # The server to use for the ADSI connection.
14 | [String]$Server,
15 |
16 | # Credentials to use when connecting to the server.
17 | [PSCredential]$Credential
18 | )
19 |
20 | $rootDSE = NewDirectoryEntry -DistinguishedName 'RootDSE' @psboundparameters
21 | $properties = @{}
22 | foreach ($property in $rootDSE.Properties.Keys) {
23 | $properties.Add($property, $rootDSE.Properties[$property])
24 | }
25 | [PSCustomObject]$properties
26 | }
--------------------------------------------------------------------------------
/RDCManager/private/ADSI/NewDirectoryEntry.ps1:
--------------------------------------------------------------------------------
1 | function NewDirectoryEntry {
2 | <#
3 | .SYNOPSIS
4 | Creates a System.DirectoryServices.DirectoryEntry object.
5 | .DESCRIPTION
6 | Creates a System.DirectoryServices.DirectoryEntry object.
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | # The distinguished name to connect to.
12 | [String]$DistinguishedName,
13 |
14 | # The server used for the connection.
15 | [String]$Server,
16 |
17 | # Any credentials which should be used.
18 | [PSCredential]$Credential
19 | )
20 |
21 | if ($Server) {
22 | $Path = 'LDAP://{0}/{1}' -f $Server, $DistinguishedName
23 | } else {
24 | $Path = 'LDAP://{0}' -f $DistinguishedName
25 | }
26 | if ($Credential) {
27 | [ADSI]::new($Path, $Credential.Username, $Credential.GetNetworkCredential().Password)
28 | } else {
29 | [ADSI]::new($Path)
30 | }
31 | }
--------------------------------------------------------------------------------
/RDCManager/private/CommandAdapter/GetADComputer.ps1:
--------------------------------------------------------------------------------
1 | function GetADComputer {
2 | <#
3 | .SYNOPSIS
4 | Use either the ActiveDirectory module or ADSI to find computer objects.
5 | .DESCRIPTION
6 | Use either the ActiveDirectory module or ADSI to find computer objects.
7 | #>
8 |
9 | [CmdletBinding(DefaultParameterSetName = 'UsingFilter')]
10 | param (
11 | # A filter to use for the search. If using the ActiveDirectory module this can either be an LDAP filter, or the specialised form used by the ActiveDirectory module.
12 | [Parameter(ParameterSetName = 'UsingFilter')]
13 | [String]$Filter,
14 |
15 | # When searching by name the names are assembled into a filter for each name using the OR operator.
16 | [Parameter(ParameterSetName = 'ByName')]
17 | [String[]]$Name,
18 |
19 | # A searchbase to use. If a search base is not set, the root of the current domain is used.
20 | [String]$SearchBase,
21 |
22 | # The search scope for the search operation.
23 | [System.DirectoryServices.SearchScope]$SearchScope,
24 |
25 | # Limit the number of results returned by a search. By default result set size is unlimited.
26 | [Int32]$ResultSetSize,
27 |
28 | # The server to use for the search.
29 | [String]$Server,
30 |
31 | # Credentials to use when connecting to the server.
32 | [PSCredential]$Credential,
33 |
34 | # The filter format to use.
35 | [String]$FilterFormat = (Get-RdcConfiguration -Name FilterFormat)
36 | )
37 |
38 | $null = $psboundparameters.Remove('FilterFormat')
39 | if ($pscmdlet.ParameterSetName -eq 'ByName') {
40 | $null = $psboundparameters.Remove('Name')
41 |
42 | $FilterFormat = 'LDAP'
43 | $nameFilters = foreach ($value in $Name) {
44 | '(name={0})' -f $value
45 | }
46 | $Filter = '(|{0})' -f (-join $nameFilters)
47 | $psboundparameters.Add('Filter', $Filter)
48 | }
49 |
50 | if (Get-RdcConfiguration -Name SearchMode -Eq ADModule) {
51 | if ($FilterFormat -eq 'LDAP') {
52 | $null = $psboundparameters.Remove('Filter')
53 | $psboundparameters.Add('LdapFilter', $Filter)
54 | }
55 | Get-ADComputer -Properties dnsHostName, displayName @psboundparameters
56 | } else {
57 | GetAdsiComputer @psboundparameters
58 | }
59 | }
--------------------------------------------------------------------------------
/RDCManager/private/CommandAdapter/GetADObject.ps1:
--------------------------------------------------------------------------------
1 | function GetADObject {
2 | <#
3 | .SYNOPSIS
4 | Use either the ActiveDirectory module or ADSI to find arbitrary objects.
5 | .DESCRIPTION
6 | Use either the ActiveDirectory module or ADSI to find arbitrary objects.
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | # A filter to use for the search. If using the ActiveDirectory module this can either be an LDAP filter, or the specialised form used by the ActiveDirectory module.
12 | [String]$Filter,
13 |
14 | # A searchbase to use. If a search base is not set, the root of the current domain is used.
15 | [String]$SearchBase,
16 |
17 | # The search scope for the search operation.
18 | [System.DirectoryServices.SearchScope]$SearchScope,
19 |
20 | # The server to use for the search.
21 | [String]$Server,
22 |
23 | # Credentials to use when connecting to the server.
24 | [PSCredential]$Credential
25 | )
26 |
27 | $null = $psboundparameters.Remove('FilterFormat')
28 | if ($pscmdlet.ParameterSetName -eq 'ByName') {
29 | $null = $psboundparameters.Remove('Name')
30 |
31 | $FilterFormat = 'LDAP'
32 | $nameFilters = foreach ($value in $Name) {
33 | '(name={0})' -f $value
34 | }
35 | $Filter = '(|{0})' -f (-join $nameFilters)
36 | $psboundparameters.Add('Filter', $Filter)
37 | }
38 |
39 | if (Get-RdcConfiguration -Name SearchMode -Eq ADModule) {
40 | if ($FilterFormat -eq 'LDAP') {
41 | $null = $psboundparameters.Remove('Filter')
42 | $psboundparameters.Add('LdapFilter', $Filter)
43 | }
44 | Get-ADComputer @psboundparameters
45 | } else {
46 | GetAdsiObject @psboundparameters
47 | }
48 | }
--------------------------------------------------------------------------------
/RDCManager/private/CommandAdapter/GetADOrganizationalUnit.ps1:
--------------------------------------------------------------------------------
1 | function GetADOrganizationalUnit {
2 | <#
3 | .SYNOPSIS
4 | Use either the ActiveDirectory module or ADSI to find organizational unit objects.
5 | .DESCRIPTION
6 | Use either the ActiveDirectory module or ADSI to find organizational unit objects.
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | [Parameter(ParameterSetName = 'ByName')]
12 | [String]$Name,
13 |
14 | # A filter to use for the search. If using the ActiveDirectory module this can either be an LDAP filter, or the specialised form used by the ActiveDirectory module.
15 | [Parameter(ParameterSetName = 'UsingFilter')]
16 | [String]$Filter,
17 |
18 | # Use identity instead of a filter to locate the OU.
19 | [Parameter(ParameterSetName = 'ByIdentity')]
20 | [String]$Identity,
21 |
22 | # A searchbase to use. If a search base is not set, the root of the current domain is used.
23 | [String]$SearchBase,
24 |
25 | # The search scope for the search operation.
26 | [System.DirectoryServices.SearchScope]$SearchScope,
27 |
28 | # The server to use for the search.
29 | [String]$Server,
30 |
31 | # Credentials to use when connecting to the server.
32 | [PSCredential]$Credential,
33 |
34 | # The filter format to use.
35 | [String]$FilterFormat = (Get-RdcConfiguration -Name FilterFormat)
36 | )
37 |
38 | if ($pscmdlet.ParameterSetName -eq 'ByName') {
39 | $null = $psboundparameters.Remove('Name')
40 |
41 | $FilterFormat = 'LDAP'
42 | $Filter = '(name={0})' -f $Name
43 | $psboundparameters.Add('Filter', $Filter)
44 | }
45 |
46 | if (-not $SearchBase) {
47 | $null = $psboundparameters.Remove('SearchBase')
48 | }
49 |
50 | if (Get-RdcConfiguration -Name SearchMode -Eq ADModule) {
51 | if ($FilterFormat -eq 'LDAP') {
52 | $null = $psboundparameters.Remove('Filter')
53 | $psboundparameters.Add('LdapFilter', $Filter)
54 | }
55 | Get-ADOrganizationalUnit @psboundparameters
56 | } else {
57 | GetAdsiOrganizationalUnit @psboundparameters
58 | }
59 | }
--------------------------------------------------------------------------------
/RDCManager/public/Configuration/Get-RdcConfiguration.ps1:
--------------------------------------------------------------------------------
1 | function Get-RdcConfiguration {
2 | <#
3 | .SYNOPSIS
4 | Get the configuration for the document generator.
5 | .DESCRIPTION
6 | Get the configuration for the document generator.
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | # Get a specific configuration value by name.
12 | [String]$Name,
13 |
14 | # Get a configuration value and test whether or not it is equal to the specified value.
15 | [Object]$Eq
16 | )
17 |
18 | if ($Name -and $psboundparameters.ContainsKey('Eq')) {
19 | $script:Configuration.$Name -eq $Eq
20 | } elseif ($Name) {
21 | $Script:configuration.$Name
22 | } else {
23 | $Script:configuration
24 | }
25 | }
--------------------------------------------------------------------------------
/RDCManager/public/Configuration/Set-RdcConfiguration.ps1:
--------------------------------------------------------------------------------
1 | function Set-RdcConfiguration {
2 | <#
3 | .SYNOPSIS
4 | Set the configuration for the document generator.
5 | .DESCRIPTION
6 | Sets the configuration used by the document generator.
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | # Set the search mode used when building content from AD.
12 | #
13 | # The following values may be set:
14 | #
15 | # - ADModule: Uses the MS ActiveDirectory module.
16 | # - ADSI: Uses the ADSI search commands in this module.
17 | #
18 | # The default search mode is ADModule if the ActiveDirectory module is available on the computer. Otherwise the search mode defaults to ADSI.
19 | #
20 | # If the ActiveDirectory module is made available using implicit remoting this option must be set.
21 | [Parameter(ParameterSetName = 'Update')]
22 | [ValidateSet('ADModule', 'ADSI')]
23 | [String]$SearchMode,
24 |
25 | # The format used for filters. By default LDAP format is used when the search mode is ADSI. The ActiveDirectory format is used if the module is used.
26 | [Parameter(ParameterSetName = 'Update')]
27 | [ValidateSet('ADModule', 'LDAP')]
28 | [String]$FilterFormat,
29 |
30 | # Reset the configuration to the default.
31 | [Parameter(ParameterSetName = 'Reset')]
32 | [Switch]$Reset
33 | )
34 |
35 | if ($pscmdlet.ParameterSetName -eq 'Reset') {
36 | [Boolean]$isADModulePresent = Get-Module ActiveDirectory -ListAvailable
37 |
38 | $Script:configuration = [PSCustomObject]@{
39 | SearchMode = ('ADSI', 'ADModule')[$isADModulePresent]
40 | FilterFormat = ('LDAP', 'ADModule')[$isADModulePresent]
41 | }
42 | } else {
43 | if ($SearchMode -and -not $FilterFormat) {
44 | if ($SearchMode -eq 'ADSI') {
45 | $psboundparameters['FilterFormat'] = 'LDAP'
46 | } else {
47 | $psboundparameters['FilterFormat'] = 'ADModule'
48 | }
49 | }
50 |
51 | foreach ($parameterName in $psboundparameters.Keys) {
52 | if ($Script:configuration.PSObject.Properties.Item($parameterName)) {
53 | $Script:configuration.$parameterName = $psboundparameters[$parameterName]
54 | }
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/ADConfiguration.ps1:
--------------------------------------------------------------------------------
1 | function ADConfiguration {
2 | <#
3 | .SYNOPSIS
4 | Set the AD any AD configuration which should be used when searching Active Directory.
5 | .DESCRIPTION
6 | The ADConfiguration element provides default values for AD search operations in child scopes.
7 |
8 | The ADConfiguration element is expected to be used in RdcDocument or RdcGroup elements.
9 | #>
10 |
11 | [CmdletBinding()]
12 | param (
13 | [Parameter(Mandatory)]
14 | [ValidateScript(
15 | {
16 | if ($_.ContainsKey('Credential') -and $_['Credential'] -isnot [PSCredential]) {
17 | throw 'The credential key was present, but the value is not a credential object.'
18 | }
19 | foreach ($key in $_.Keys) {
20 | if ($key -notin 'Server', 'Credential') {
21 | throw ('Invalid key in the ADConfigurastion hashtable. Valid keys are Server and Credential')
22 | }
23 | }
24 | $true
25 | }
26 | )]
27 | [Hashtable]$ADConfiguration
28 | )
29 |
30 | try {
31 | # Get the value of the parentNode variable from the parent scope(s)
32 | $parentNode = Get-Variable currentNode -ValueOnly -ErrorAction Stop
33 | } catch {
34 | throw ('{0} must be nested in RdcDocument or RdcGroup: {1}' -f $myinvocation.InvocationName, $_.Exception.Message)
35 | }
36 |
37 | foreach ($key in $ADConfiguration.Keys) {
38 | New-Variable -Name ('RdcAD{0}' -f $key) -Value $ADConfiguration[$key] -Scope 1 -Force
39 | }
40 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/RdcADComputer.ps1:
--------------------------------------------------------------------------------
1 | function RdcADComputer {
2 | <#
3 | .SYNOPSIS
4 | Creates a set of computers under a document or group.
5 | .DESCRIPTION
6 | RdcADComputer is used to create computer objects based on a search of Active Directory.
7 | #>
8 |
9 | [CmdletBinding(DefaultParameterSetName = 'UsingFilter')]
10 | param (
11 | # The filter which will be used to find computers.
12 | [Parameter(Position = 1, ParameterSetName = 'UsingFilter')]
13 | [String]$Filter = '*',
14 |
15 | # When searching by name the names are assembled into a filter for each name using the OR operator.
16 | [Parameter(ParameterSetName = 'ByName')]
17 | [String[]]$Name,
18 |
19 | # The search base. By default the search is performed from the root of the current domain.
20 | [String]$SearchBase,
21 |
22 | # The server to use for this operation.
23 | [String]$Server = (Get-Variable RdcADServer -ValueOnly -ErrorAction SilentlyContinue),
24 |
25 | # Credentials to use when connecting to active directory.
26 | [PSCredential]$Credential = (Get-Variable RdcADCredential -ValueOnly -ErrorAction SilentlyContinue),
27 |
28 | # If recurse is set computer objects from child OUs will be added to the parent group.
29 | [Switch]$Recurse
30 | )
31 |
32 | if (-not $psboundparameters.ContainsKey('SearchBase')) {
33 | if ($candidateDN = Get-Variable parentDN -ValueOnly -ErrorAction SilentlyContinue) {
34 | $SearchBase = $candidateDN
35 | }
36 | }
37 |
38 | $params = @{
39 | SearchBase = $SearchBase
40 | SearchScope = ('OneLevel', 'Subtree')[$Recurse.ToBool()]
41 | }
42 | if ($Name) {
43 | $params.Add('Name', $Name)
44 | } else {
45 | $params.Add('Filter', $Filter)
46 | }
47 | if ($Server) {
48 | $params.Add('Server', $Server)
49 | }
50 | if ($Credential) {
51 | $params.Add('Credential', $Credential)
52 | }
53 |
54 | GetADComputer @params |
55 | Sort-Object Name |
56 | RdcComputer
57 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/RdcADGroup.ps1:
--------------------------------------------------------------------------------
1 | function RdcADGroup {
2 | <#
3 | .SYNOPSIS
4 | Create a group node derived from the content of an organisational unit.
5 | .DESCRIPTION
6 | Create a group node derived from the content of an organisational unit.
7 | #>
8 |
9 | [CmdletBinding(DefaultParameterSetName = 'UsingFilter')]
10 | param (
11 | # The identity of a single OU.
12 | [Parameter(Mandatory, Position = 1, ParameterSetName = 'ByName')]
13 | [String]$Name,
14 |
15 | # A filter for OU objects.
16 | [Parameter(ParameterSetName = 'UsingFilter')]
17 | [String]$Filter = '*',
18 |
19 | # The identity of a single OU.
20 | [Parameter(Mandatory, ParameterSetName = 'ByIdentity')]
21 | [String]$Identity,
22 |
23 | # A filter to apply when evaluating descendent computer objects.
24 | [String]$ComputerFilter = '*',
25 |
26 | # The search base to use when using a filter.
27 | [Parameter(ParameterSetName = 'UsingFilter')]
28 | [String]$SearchBase,
29 |
30 | # The server to use for this operation.
31 | [String]$Server = (Get-Variable RdcADServer -ValueOnly -ErrorAction SilentlyContinue),
32 |
33 | # Credentials to use when connecting to active directory.
34 | [PSCredential]$Credential = (Get-Variable RdcADCredential -ValueOnly -ErrorAction SilentlyContinue),
35 |
36 | # If Recurse is set, groups will be created in the RDC document reprsenting each child organisational unit.
37 | #
38 | # Organizational units are only included as groups if the oganizational unit contains computer accounts or other organizational units.
39 | [Switch]$Recurse
40 | )
41 |
42 | if (-not $psboundparameters.ContainsKey('SearchBase')) {
43 | if ($candidateDN = Get-Variable parentDN -ValueOnly -ErrorAction SilentlyContinue) {
44 | $SearchBase = $candidateDN
45 | }
46 | }
47 |
48 | if ($pscmdlet.ParameterSetName -eq 'ByIdentity') {
49 | $params = @{
50 | Identity = $Identity
51 | }
52 | } elseif ($pscmdlet.ParameterSetName -eq 'ByName') {
53 | $params = @{
54 | Name = $Name
55 | SearchBase = $SearchBase
56 | SearchScope = 'Subtree'
57 | }
58 | } else {
59 | $params = @{
60 | Filter = $Filter
61 | SearchBase = $SearchBase
62 | SearchScope = 'OneLevel'
63 | }
64 | }
65 |
66 | $serverAndCredential = @{}
67 | if ($Server) {
68 | $serverAndCredential.Add('Server', $Server)
69 | }
70 | if ($Credential) {
71 | $serverAndCredential.Add('Credential', $Credential)
72 | }
73 |
74 | GetADOrganizationalUnit @params @serverAndCredential | ForEach-Object {
75 | # Determine if the OU has child objects. If so, allow it to be included.
76 | Write-Debug 'Searching for child computer objects'
77 | Write-Debug (' SearchBase: {0}' -f $_.DistinguishedName)
78 |
79 | $params = @{
80 | Filter = '*'
81 | SearchBase = $_.DistinguishedName
82 | SearchScope = 'Subtree'
83 | ResultSetSize = 1
84 | }
85 | if (GetADComputer @params @serverAndCredential) {
86 | Write-Verbose ('Creating group {0}' -f $_.Name)
87 |
88 | $parentDN = $_.DistinguishedName
89 | if ($Recurse) {
90 | RdcGroup $_.Name {
91 | RdcADGroup -Recurse -ComputerFilter $ComputerFilter @serverAndCredential
92 | RdcADComputer -Filter $ComputerFilter @serverAndCredential
93 | }
94 | } else {
95 | RdcGroup $_.Name {
96 | RdcADComputer -Filter $ComputerFilter @serverAndCredential -Recurse
97 | }
98 | }
99 | }
100 | }
101 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/RdcComputer.ps1:
--------------------------------------------------------------------------------
1 | function RdcComputer {
2 | <#
3 | .SYNOPSIS
4 | Create a computer in the RDCMan document.
5 | .DESCRIPTION
6 | Create a computer in the RDCMan document.
7 | #>
8 |
9 | [CmdletBinding(DefaultParameterSetName = 'FromPipeline')]
10 | param (
11 | [Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = 'FromPipeline')]
12 | [String]$Name,
13 |
14 | [Parameter(Position = 2, ValueFromPipelineByPropertyName, ParameterSetName = 'FromPipeline')]
15 | [String]$DnsHostName,
16 |
17 | [Parameter(Position = 3, ValueFromPipelineByPropertyName, ParameterSetName = 'FromPipeline')]
18 | [Alias('IPv4Address')]
19 | [String]$Comment,
20 |
21 | [Parameter(Mandatory, Position = 1, ParameterSetName = 'FromHashtable')]
22 | [ValidateScript(
23 | {
24 | if (-not $_.ContainsKey('Name')) {
25 | throw 'The Name key must be present'
26 | }
27 | foreach ($key in $_.Keys) {
28 | if ($key -notin 'Name', 'DnsHostName', 'Comment') {
29 | throw ('Invalid key in Properties hashtable. Valid keys are Name, DnsHostName, and Comment')
30 | }
31 | }
32 | $true
33 | }
34 | )]
35 | [Hashtable]$Properties
36 | )
37 |
38 | begin {
39 | try {
40 | # Get the value of the parentNode variable from the parent scope(s)
41 | $parentNode = Get-Variable currentNode -ValueOnly -ErrorAction Stop
42 | } catch {
43 | throw ('{0} must be nested in RdcDocument or RdcGroup: {1}' -f $myinvocation.InvocationName, $_.Exception.Message)
44 | }
45 | }
46 |
47 | process {
48 | if ($Properties) {
49 | $Name = $Properties.Name
50 | $DnsHostName = $Properties.DnsHostName
51 | $Comment = $Properties.Comment
52 | }
53 | if (-not $DnsHostName) {
54 | $DnsHostName = $Name
55 | }
56 |
57 | $xElement = [System.Xml.Linq.XElement]('
58 |
59 |
60 | {0}
61 | {1}
62 | {2}
63 |
64 | ' -f $Name, $DnsHostName, $Comment)
65 |
66 | if ($parentNode -is [System.Xml.Linq.XDocument]) {
67 | $parentNode.Element('Rdc').Element('connected').AddBeforeSelf($xElement)
68 | } else {
69 | $parentNode.Element('properties').AddAfterSelf($xElement)
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/RdcConfiguration.ps1:
--------------------------------------------------------------------------------
1 | function RdcConfiguration {
2 | <#
3 | .SYNOPSIS
4 |
5 | .DESCRIPTION
6 | RdcConfiguration allows the generator behaviours to be defined using a node in the document.
7 | .EXAMPLE
8 | RdcDocument name {
9 | RdcConfiguration @{
10 | SearchMode = 'ADSI'
11 | }
12 | }
13 | #>
14 |
15 | [CmdletBinding()]
16 | param (
17 | [Parameter(Mandatory)]
18 | [Hashtable]$Configuration
19 | )
20 |
21 | Set-RdcConfiguration @Configuration
22 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/RdcDocument.ps1:
--------------------------------------------------------------------------------
1 | function RdcDocument {
2 | <#
3 | .SYNOPSIS
4 | Declare an RDCMan document.
5 | .DESCRIPTION
6 | An RDC Document defines the basic document content and is the starting point for creating groups and computer elements.
7 | #>
8 |
9 | [CmdletBinding()]
10 | param (
11 | # The path to a file to save content.
12 | [Parameter(Mandatory, Position = 1)]
13 | [Alias('FileName', 'FullName')]
14 | [String]$Path,
15 |
16 | # A script block defining the content of the document.
17 | [Parameter(Mandatory, Position = 2)]
18 | [ScriptBlock]$Children
19 | )
20 |
21 | $xDocument = $currentNode = [System.Xml.Linq.XDocument]::Parse('
22 |
23 |
24 |
25 |
26 |
27 | {0}
28 |
29 |
30 |
31 |
32 |
33 | '.Trim() -f ([System.IO.FileInfo]$Path).BaseName)
34 |
35 | if ($Children) {
36 | & $Children
37 | }
38 |
39 | if ($Path -notmatch '\.rdg$') {
40 | $Path = '{0}.rdg' -f $Path
41 | }
42 | $Path = $pscmdlet.GetUnresolvedProviderPathFromPSPath($Path)
43 | $xDocument.Save($Path)
44 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/RdcGroup.ps1:
--------------------------------------------------------------------------------
1 | function RdcGroup {
2 | [CmdletBinding()]
3 | param (
4 | [Parameter(Mandatory, ValueFromPipeline, Position = 1)]
5 | [String]$Name,
6 |
7 | [Parameter(Mandatory, Position = 2)]
8 | [ScriptBlock]$Children
9 | )
10 |
11 | try {
12 | # Get the value of the parentNode variable from the parent scope(s)
13 | $parentNode = Get-Variable currentNode -ValueOnly -ErrorAction Stop
14 | } catch {
15 | throw ('{0} must be nested in RdcDocument or RdcGroup: {1}' -f $myinvocation.InvocationName, $_.Exception.Message)
16 | }
17 |
18 | $xElement = $currentNode = [System.Xml.Linq.XElement]::new('group',
19 | [System.Xml.Linq.XElement]::new('properties',
20 | [System.Xml.Linq.XElement]::new('name', $Name)
21 | )
22 | )
23 |
24 | if ($parentNode -is [System.Xml.Linq.XDocument]) {
25 | $parentNode.Element('Rdc').Element('file').Add($xElement)
26 | } else {
27 | $parentNode.Add($xElement)
28 | }
29 |
30 | if ($Children) {
31 | & $Children
32 | }
33 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/RdcLogonCredential.ps1:
--------------------------------------------------------------------------------
1 | function RdcLogonCredential {
2 | <#
3 | .SYNOPSIS
4 | Creates a node to save credentials in the parent group or document.
5 | .DESCRIPTION
6 | Creates a node to save credentials in the parent group or document.
7 | #>
8 |
9 | [CmdletBinding(DefaultParameterSetName = 'FromHashtable')]
10 | param (
11 | [Parameter(Position = 1, ParameterSetName = 'FromHashtable')]
12 | [ValidateScript(
13 | {
14 | if ($_.Contains('Password') -and $_['Password'] -isnot [SecureString]) {
15 | throw 'Passwords must be stored as a secure string'
16 | }
17 | foreach ($key in $_.Keys) {
18 | if ($key -notin 'Username', 'Password', 'Domain') {
19 | throw ('Invalid key in the RdcLogonCredentials hashtable. Valid keys are UserName, Password, and Domain')
20 | }
21 | }
22 | $true
23 | }
24 | )]
25 | [Hashtable]$CredentialHash,
26 |
27 | [Parameter(ParameterSetName = 'FromCredential')]
28 | [PSCredential]$Credential,
29 |
30 | [Switch]$SavePassword
31 | )
32 |
33 | try {
34 | # Get the value of the parentNode variable from the parent scope(s)
35 | $parentNode = Get-Variable currentNode -ValueOnly -ErrorAction Stop
36 | } catch {
37 | throw ('{0} must be nested in RdcDocument or RdcGroup: {1}' -f $myinvocation.InvocationName, $_.Exception.Message)
38 | }
39 |
40 | if ($Credential) {
41 | if ($Credential.Username.Contains('\')) {
42 | $domainName, $username = $Credential.UserName -split '\\', 2
43 | } else {
44 | $domainName = ''
45 | $userName = $Credential.UserName
46 | }
47 | $secureString = $Credential.Password
48 | } else {
49 | $domainName = $CredentialHash['Domain']
50 | $userName = $CredentialHash['UserName']
51 | $secureString = $CredentialHash['Password']
52 | }
53 |
54 | if ($secureString.Length -gt 0) {
55 | $encryptedHexString = $secureString | ConvertFrom-SecureString
56 | $bytes = for ($i = 0; $i -lt $encryptedHexString.Length; $i += 2) {
57 | [Convert]::ToByte(
58 | ('{0}{1}' -f $encryptedHexString[$i], $encryptedHexString[$i + 1]),
59 | 16
60 | )
61 | }
62 | $encryptedPassword = [Convert]::ToBase64String($bytes)
63 | } else {
64 | $encryptedPassword = ''
65 | }
66 |
67 | # V2: BigInteger variation
68 |
69 | # Add-Type -AssemblyName System.Numerics
70 | # $bytes = [System.Numerics.BigInteger]::Parse(
71 | # ($secureString | ConvertFrom-SecureString),
72 | # 'HexNumber'
73 | # ).ToByteArray()
74 | # [Array]::Reverse($bytes)
75 |
76 | # $encryptedString = [Convert]::ToBase64String($bytes)
77 |
78 | # [RdcMan.Encryption]::DecryptString($encryptedString, [RdcMan.EncryptionSettings]::new())
79 |
80 | # V3: Decrypt and reencrypt
81 |
82 | # $encryptedString = [Convert]::ToBase64String(
83 | # [System.Security.Cryptography.ProtectedData]::Protect(
84 | # [System.Text.Encoding]::Unicode.GetBytes(
85 | # $Credential.GetNetworkCredential().Password
86 | # ),
87 | # $null,
88 | # 'CurrentUser'
89 | # )
90 | # )
91 |
92 | $xElement = [System.Xml.Linq.XElement]('
93 |
94 | Custom
95 | {0}
96 | {1}
97 | {2}
98 | ' -f $username, $encryptedPassword, $domainName)
99 |
100 | if ($parentNode.NodeType -eq 'Document') {
101 | $propertiesElement = $parentNode.FirstNode.Element('file').Element('properties')
102 | }
103 | else {
104 | $propertiesElement = $parentNode.Element('properties')
105 | }
106 | $propertiesElement.AddAfterSelf($xElement)
107 | }
--------------------------------------------------------------------------------
/RDCManager/public/DSL/RdcRemoteDesktopSetting.ps1:
--------------------------------------------------------------------------------
1 | function RdcRemoteDesktopSetting {
2 | <#
3 | .SYNOPSIS
4 | Creates a node to configure remote desktop settings in the parent group or document.
5 | .DESCRIPTION
6 | Creates a node to configure remote desktop settings in the parent group or document.
7 | #>
8 |
9 | [CmdletBinding(DefaultParameterSetName = 'FromHashtable')]
10 | param (
11 | # Remote Destkop Settings configuration.
12 | #
13 | # Remote destkop settings allows the following to be defined:
14 | #
15 | # - Size - A value in the form Horizontal x Vertical.
16 | # - SameSizeAsClientArea - True or False. Make the remote desktop area fill the client window pane.
17 | # - FullScreen - True or False. Make the remote desktop full screen.
18 | # - ColorDepth - By default 24. ColorDepth can be set to 8, 15, 16, 24, or 32.
19 | [Parameter(Position = 1, ParameterSetName = 'FromHashtable')]
20 | [ValidateScript(
21 | {
22 | foreach ($key in $_.Keys) {
23 | if ($key -notin 'Size', 'SameSizeAsClientArea', 'FullScreen', 'ColorDepth') {
24 | throw ('Invalid key in the RdcLogonCredentials hashtable. Valid keys are Size, SameSizeAsClientArea, FullScreen, and ColorDepth')
25 | }
26 | }
27 | $true
28 | }
29 | )]
30 | [Hashtable]$SettingsHash
31 | )
32 |
33 | try {
34 | # Get the value of the parentNode variable from the parent scope(s)
35 | $parentNode = Get-Variable currentNode -ValueOnly -ErrorAction Stop
36 | } catch {
37 | throw ('{0} must be nested in RdcDocument or RdcGroup: {1}' -f $myinvocation.InvocationName, $_.Exception.Message)
38 | }
39 |
40 | $settings = @{
41 | Size = $null
42 | SameSizeAsClientArea = $false
43 | FullScreen = $true
44 | ColorDepth = 24
45 | }
46 | foreach ($setting in $SettingsHash.Keys) {
47 | $settings[$setting] = $settingsHash[$setting]
48 | }
49 | if ($SettingsHash.Contains('SameSizeAsClientArea') -and $SettingsHash['SameSizeAsClientArea']) {
50 | $settings['FullScreen'] = $false
51 | }
52 |
53 | if ($settings['ColorDepth'] -notin 8, 15, 16, 24, 32) {
54 | throw 'Invalid color depth. Valid values are 8, 15, 16, 24, and 32.'
55 | }
56 | if ($settings['Size'] -and $settings['Size'] -notmatch '^\d+ *x *\d+$') {
57 | throw 'Invalid desktop size. Sizes must be specified in the format "Horizontal x Vertical"'
58 | } elseif ($settings['Size'] -match '^(\d+) *x *(\d+)$') {
59 | # Ensure Size is formatted exactly as RdcMan expects it to be.
60 | $settings['Size'] = '{0} x {1}' -f $matches[1], $matches[2]
61 | }
62 |
63 | $xElement = [System.Xml.Linq.XElement]('
64 |
65 | {0}
66 | {1}
67 | {2}
68 | ' -f $settings['SameSizeAsClientArea'], $settings['FullScreen'], $settings['ColorDepth'])
69 |
70 | if (-not $settings['FullScreen'] -and $settings['Size']) {
71 | $null = $xElement.Element('remoteDestkop').AddFirst(
72 | [System.Xml.Linq.XElement]('{0}' -f $settings['Size'])
73 | )
74 | }
75 |
76 | if ($parentNode -is [System.Xml.Linq.XDocument]) {
77 | $parentNode.Element('Rdc').Element('file').Add($xElement)
78 | } else {
79 | $parentNode.Add($xElement)
80 | }
81 | }
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | [cmdletbinding()]
2 | param (
3 | $SourceFolder = "$PSScriptRoot",
4 | $Destination = "$PSScriptRoot\out"
5 | )
6 |
7 | function Get-FilesToMerge {
8 | [cmdletbinding()]
9 | param (
10 | $Path = $PSScriptRoot
11 | )
12 |
13 | Get-ChildItem -Path $PSScriptRoot -Recurse -Include *.ps1 -Exclude build.ps1 |
14 | Sort-Object FullName | ForEach-Object {
15 | "Adding {0} to the psm1 file" -f $_.BaseName | Write-Verbose
16 | Get-Content -Path $_.FullName | Add-Content -Path $PSScriptRoot\out\RDCManager\RDCManager.psm1
17 | "`r" | Add-Content -Path $PSScriptRoot\out\RDCManager\RDCManager.psm1
18 | }
19 | }
20 |
21 | # Remove out directory to allow rebuilding
22 | if (Test-Path -Path $PSScriptRoot\out) {
23 | Remove-Item -Path $Destination -Force -Confirm:$false -Recurse
24 | }
25 |
26 | $null = New-Item -ItemType Directory -Name RDCManager -Path $PSScriptRoot\out
27 |
28 | Get-FilesToMerge
29 |
30 | "Adding InitializeModule to the psm1 file" | Write-Verbose
31 | "InitializeModule" | Add-Content -Path $PSScriptRoot\out\RDCManager\RDCManager.psm1
32 |
33 | "Copying Manifest file to {0}" -f $Destination | Write-Verbose
34 | Copy-Item -Path $PSScriptRoot\RDCManager\*.psd1 -Destination $PSScriptRoot\out\RDCManager
35 |
36 | #$content -replace "^FunctionsToExport = '[*]'$", ("FunctionsToExport = @('{0}'`r`n)" -f ($pubfunctions -join "',`r`n`t'"))
37 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 |  [](https://dev.azure.com/brettmillerb/RDCMan/_build/latest?definitionId=1&branchName=master)
2 |
3 | # Remote Desktop Manager File Generator
4 |
5 | ~~Idea taken from Kevin Marquette's RDCMan DSL to generate the entire XML for a new file.~~
6 |
7 | Now **very** loosely based on Kevin Marquette's RDCMan DSL blog post
8 |
9 | https://kevinmarquette.github.io/2017-03-04-Powershell-DSL-example-RDCMan/
10 |
11 | Entirely reworked by [Chris Dent - Indented Automation](https://github.com/indented-automation)
12 |
13 | ## Usage
14 | RDCManager alllows you to group servers and store configuration data so you can effectively manage your server estate from one window.
15 |
16 | This module allows you to dynamically create the document for RDCManager by extracting the data from Active Directory. This saves you having to remember to add/remove servers as they change in your estate.
17 |
18 | The module offers the option of using the Active Directory module if RSAT tools are installed otherwise you can specify to use LDAP to perform queries.
19 |
20 | ## Generating the document
21 |
22 | ### RdcDocument
23 | This must be specified as this is the starting point for you to begin defining groups/computers.
24 |
25 | You can then define your document manually with the `RdcGroup` and `RdcComputer` functions.
26 |
27 | ```powershell
28 | RdcDocument MyServers {
29 | RdcGroup "My First Group" {
30 | RdcComputer -Name 'server001' -DnsHostName 'server001.fqdn.com' -IPv4address '10.0.0.1'
31 | RdcComputer -Name 'server002' -DnsHostName 'server002.fqdn.com' -IPv4address '10.0.0.2'
32 | }
33 | }
34 | ```
35 | #### Output
36 | 
37 |
38 | ### Generating a file with specific Active Directory filtering
39 | ```powershell
40 | RdcDocument MyServers {
41 | RdcGroup "My Group" {
42 | # Will create a group with the OU name and any computer objects within
43 | RdcADGroup -Identity 'OU=Newcastle,DC=millerb,DC=co,DC=uk'
44 |
45 | #Add -Recurse switch and it will create a group for each sub OU and add members accordingly
46 | RdcADGroup -Identity 'OU=London,DC=millerb,DC=co,DC=uk' -Recurse
47 |
48 | # Will search for a specific server provided by the filter recursing all OU's
49 | RdcADComputer -Name 'Admin*' -Recurse
50 | }
51 | }
52 | ```
53 |
54 | ### Automatic creation from root of domain
55 | This will create groups replicating the OU structure which contains computer objects.
56 |
57 | ```powershell
58 | RdcDocument 'Domain' {
59 | RdcADGroup -Recurse
60 | }
61 | ```
62 |
63 | #### Output
64 | 
65 |
66 | ## Additional Functionality
67 |
68 | #### RdcConfiguration
69 | Sets the configuration to be used when generating the document. This is not required as if the AD module is detected this will be used unless ADSI is specified. If the AD Module is not available then ADSI LDAP filters will be used.
70 |
71 | ```powershell
72 | RdcConfiguration @{
73 | SearchMode = 'ADSI'
74 | FilterFormat = 'LDAP'
75 | }
76 | ```
77 |
78 | #### RdcLogonCredential
79 | Allows credentials to be set at any level to support different domains/forests. May conflict with GPO's set to prevent saved passwords being used.
80 |
81 | ```powershell
82 | RdcLogonCredential @{
83 | Username = 'millerb-admin'
84 | Domain = 'millerb.co.uk'
85 | }
86 | ```
87 | #### RdcRemoteDesktopSetting
88 | Enables scaling of the connected client window.
89 | ```powershell
90 | RdcRemoteDesktopSetting @{
91 | SameSizeAsClientArea = $true
92 | }
93 | ```
--------------------------------------------------------------------------------