Skip to content

Commit f678a6b

Browse files
committed
Added xOfflineDomainJoin resource
1 parent 42400dc commit f678a6b

6 files changed

Lines changed: 610 additions & 0 deletions

File tree

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
$moduleRoot = Split-Path `
2+
-Path $MyInvocation.MyCommand.Path `
3+
-Parent
4+
5+
#region LocalizedData
6+
$Culture = 'en-us'
7+
if (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath $PSUICulture))
8+
{
9+
$Culture = $PSUICulture
10+
}
11+
Import-LocalizedData `
12+
-BindingVariable LocalizedData `
13+
-Filename MSFT_xOfflineDomainJoin.psd1 `
14+
-BaseDirectory $moduleRoot `
15+
-UICulture $Culture
16+
#endregion
17+
18+
19+
function Get-TargetResource
20+
{
21+
[CmdletBinding()]
22+
[OutputType([Hashtable])]
23+
param
24+
(
25+
[parameter(Mandatory = $true)]
26+
[ValidateSet('Yes')]
27+
[System.String]
28+
$IsSingleInstance,
29+
30+
[parameter(Mandatory = $true)]
31+
[ValidateNotNullOrEmpty()]
32+
[System.String]
33+
$RequestFile
34+
)
35+
36+
Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): "
37+
$($LocalizedData.GettingOfflineDomainJoinMessage)
38+
) -join '')
39+
40+
# It is not possible to read the ODJ file that was used to join a domain
41+
# So it has to always be returned as blank.
42+
$returnValue = @{
43+
IsSingleInstance = 'Yes'
44+
RequestFile = ''
45+
}
46+
47+
#Output the target resource
48+
$returnValue
49+
} # Get-TargetResource
50+
51+
52+
function Set-TargetResource
53+
{
54+
[CmdletBinding()]
55+
param
56+
(
57+
[parameter(Mandatory = $true)]
58+
[ValidateSet('Yes')]
59+
[System.String]
60+
$IsSingleInstance,
61+
62+
[parameter(Mandatory = $true)]
63+
[ValidateNotNullOrEmpty()]
64+
[System.String]
65+
$RequestFile
66+
)
67+
68+
Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): "
69+
$($LocalizedData.ApplyingOfflineDomainJoinMessage)
70+
) -join '')
71+
72+
# Check the ODJ Request file exists
73+
if (-not (Test-Path -Path $RequestFile))
74+
{
75+
$errorId = 'RequestFileNotFoundError'
76+
$errorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound
77+
$errorMessage = $($LocalizedData.RequestFileNotFoundError) `
78+
-f $RequestFile
79+
$exception = New-Object -TypeName System.ArgumentException `
80+
-ArgumentList $errorMessage
81+
$errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord `
82+
-ArgumentList $exception, $errorId, $errorCategory, $null
83+
84+
$PSCmdlet.ThrowTerminatingError($errorRecord)
85+
} # if
86+
87+
# Don't need to check if the domain is already joined because
88+
# Set-TargetResource wouldn't fire unless it wasn't.
89+
Join-Domain -RequestFile $RequestFile
90+
} # Set-TargetResource
91+
92+
93+
function Test-TargetResource
94+
{
95+
[CmdletBinding()]
96+
[OutputType([Boolean])]
97+
param
98+
(
99+
[parameter(Mandatory = $true)]
100+
[ValidateSet('Yes')]
101+
[System.String]
102+
$IsSingleInstance,
103+
104+
[parameter(Mandatory = $true)]
105+
[ValidateNotNullOrEmpty()]
106+
[System.String]
107+
$RequestFile
108+
)
109+
110+
# Flag to signal whether settings are correct
111+
[Boolean] $desiredConfigurationMatch = $true
112+
113+
Write-Verbose -Message ( @("$($MyInvocation.MyCommand): "
114+
$($LocalizedData.CheckingOfflineDomainJoinMessage)
115+
) -join '')
116+
117+
# Check the ODJ Request file exists
118+
if (-not (Test-Path -Path $RequestFile))
119+
{
120+
$errorId = 'RequestFileNotFoundError'
121+
$errorCategory = [System.Management.Automation.ErrorCategory]::ObjectNotFound
122+
$errorMessage = $($LocalizedData.RequestFileNotFoundError) `
123+
-f $RequestFile
124+
$exception = New-Object -TypeName System.ArgumentException `
125+
-ArgumentList $errorMessage
126+
$errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord `
127+
-ArgumentList $exception, $errorId, $errorCategory, $null
128+
129+
$PSCmdlet.ThrowTerminatingError($errorRecord)
130+
} # if
131+
132+
$CurrentDomainName = Get-DomainName
133+
134+
if($CurrentDomainName)
135+
{
136+
# Domain is already joined.
137+
Write-Verbose -Message ( @(
138+
"$($MyInvocation.MyCommand): "
139+
$($LocalizedData.DomainAlreadyJoinedhMessage) `
140+
-f $CurrentDomainName `
141+
) -join '' )
142+
}
143+
else
144+
{
145+
# Domain is not joined, so change is required.
146+
Write-Verbose -Message ( @("$($MyInvocation.MyCommand): "
147+
$($LocalizedData.DomainNotJoinedMessage)
148+
) -join '')
149+
150+
$desiredConfigurationMatch = $false
151+
} # if
152+
return $desiredConfigurationMatch
153+
} # Test-TargetResource
154+
155+
156+
<#
157+
.SYNOPSIS
158+
Uses DJoin.exe to join a Domain using a ODJ Request File.
159+
#>
160+
function Join-Domain {
161+
[CmdletBinding()]
162+
param(
163+
[Parameter(Mandatory=$true)]
164+
[System.String]
165+
$RequestFile
166+
)
167+
168+
Write-Verbose -Message ( @(
169+
"$($MyInvocation.MyCommand): "
170+
$($LocalizedData.AttemptingDomainJoinMessage) `
171+
-f $RequestFile `
172+
) -join '' )
173+
174+
& djoin.exe /REQUESTODJ /LOADFILE $RequestFile
175+
176+
Write-Verbose -Message ( @(
177+
"$($MyInvocation.MyCommand): "
178+
$($LocalizedData.DomainJoinedMessage) `
179+
-f $RequestFile `
180+
) -join '' )
181+
} # function Join-Domain
182+
183+
184+
<#
185+
.SYNOPSIS
186+
Returns the name of the Domain the computer is joined to or
187+
$null if not domain joined.
188+
#>
189+
function Get-DomainName
190+
{
191+
[CmdletBinding()]
192+
[OutputType([System.String])]
193+
param()
194+
195+
# Use CIM to detect the domain name so that this will work on Nano Server.
196+
$ComputerSystem = Get-CimInstance -ClassName win32_computersystem -Namespace root\cimv2
197+
if ($ComputerSystem.Workgroup)
198+
{
199+
return $null
200+
}
201+
else
202+
{
203+
$ComputerSystem.Domain
204+
}
205+
} # function Get-DomainName
206+
207+
208+
Export-ModuleMember -Function *-TargetResource
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[ClassVersion("1.0.0.0"), FriendlyName("xOfflineDomainJoin")]
2+
class MSFT_xOfflineDomainJoin : OMI_BaseResource
3+
{
4+
[Key, Description("Specifies the resource is a single instance, the value must be 'Yes'"), ValueMap{"Yes"}, Values{"Yes"}] String IsSingleInstance;
5+
[Required, Description("The full path to the Offline Domain Join Request file to use.")] String RequestFile;
6+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
ConvertFrom-StringData @'
2+
GettingOfflineDomainJoinMessage=Getting the Offline Domain Join State.
3+
ApplyingOfflineDomainJoinMessage=Applying the Offline Domain Join State.
4+
AttemptingDomainJoinMessage=Attempting domain join using ODJ Request file '{0}'.
5+
DomainJoinedMessage=Domain joined using ODJ Request file '{0}'. Reboot will be required.
6+
CheckingOfflineDomainJoinMessage=Checking the Offline Domain Join State.
7+
DomainAlreadyJoinedhMessage=The computer is already joined to a domain '{0}'. Change not required.
8+
DomainNotJoinedMessage=The computer is not joined to a domain. Change required.
9+
RequestFileNotFoundError=The ODJ Request file '{0}' does not exist.
10+
'@

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ xOfflineDomainJoin resource is a [Single Instance](https://msdn.microsoft.com/en
5858
* Added the following resources:
5959
* MSFT_xOfflineDomainJoin resource to join computers to an AD Domain using an Offline Domain Join request file.
6060
* xComputer: Changed credential generation code in tests to avoid triggering PSSA rule PSAvoidUsingConvertToSecureStringWithPlainText.
61+
Renamed unit test file to match the name of Resource file.
6162

6263
### 1.5.0.0
6364
* Update Unit tests to use the standard folder structure and test templates.

0 commit comments

Comments
 (0)