-
-
Save FlorianAlikoff/8a22e4c3fd9d36417deb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
########################################################## | |
# # | |
# Script PowerShell v4.0 # | |
# Pull Server Configuration # | |
# # | |
# Name : Pull Server Configuration.ps1 # | |
# Author : Florian Alikoff # | |
# Date : 10/02/2014 # | |
# # | |
########################################################## | |
################################################################## | |
# Functions # | |
################################################################## | |
Configuration DSCPullServer { | |
<# | |
.SYNOPSIS | |
Generate pull configuration for LocalConfigurationManager ressource for specific computers. | |
.DESCRIPTION | |
Generate pull configuration for LocalConfigurationManager ressource for specific computers. | |
.PARAMETER Computer | |
Pull server name | |
.PARAMETER ShareName | |
Pull server share | |
.PARAMETER FolderName | |
Pull server share path | |
.PARAMETER FilterMode | |
Pull clients filter name (name of an organizational unit ou AD group) | |
.PARAMETER ClientFilter | |
Pull clients filter (organizational unit or AD group) | |
.PARAMETER SourceScriptPath | |
Folder path containing script (Library Pull Configuration.ps1) that will be retrieve by DSC file ressource on pull server. | |
.PARAMETER ConfigurationFolder | |
Folder containing configuration file (MOF) on pull share (containing MOF file with GUID in name and checksum files). | |
Theses files are auto generated by configuration | |
.PARAMETER OriginConfigurationFolder | |
Folder containing original configuration file (MOF) on pull share that user can modify. | |
.PARAMETER ScriptFolder | |
Folder containing functions on pull share (Library Pull Configuration.ps1). The file will be retrieve and use by the DSC configuration. | |
.PARAMETER ConfigurationModeFrequencyMins | |
Frequency between two configuration check in minutes | |
.PARAMETER RefreshFrequencyMins | |
Frequency between two refresh of configuration file in minutes (check on pull server) | |
.EXAMPLE | |
DSCPullServer -Computer "Server01" -FolderName "C:\PullDSC" -ShareName "PullDSC" -ClientFilter "Pull Clients" ` | |
-FilterMode "Group" -SourceScriptPath "C:\PullServer\Scripts" -ConfigurationFolder "Configuration" ` | |
-ConfigurationModeFrequencyMins 45 -RefreshFrequencyMins 30 ` | |
-OriginConfigurationFolder "OriginConfiguration" -ScriptFolder "Scripts" -OutputPath C:\PSDSC | |
Description | |
----------- | |
It creates a pull server on Server01. A share will be created on C:\PullDSC with name PullDSC (full path \\Server01\PullDSC). Computers | |
in Active Directory Group will become a client of this Pull server (it generates a LocalConfigurationManager configuration file for each | |
computer). You only have to Launch Set-LocalConfigurationManager on this computers. LocalconfigurationManager will be configured with | |
RefreshFrequencyMins to 30 minutes and ConfigurationModeFrequencyMins to 45 minutes. On pull share a folder named Configuration contains | |
MOF files clients computer retrieve (named with a guid) and a checkum file for each MOF file to verify their integrity. Theses files are | |
generated automatically by retrieving MOF files created by User on OriginConfiguration folder. Finally there is a Scripts folder containing | |
powershell script (Library Pull Configuration.ps1) present in C:\PullServer\Scripts. This script (mandatory) is a library to generated | |
automatically configuration for clients Computer. | |
#> | |
param( | |
[Parameter(Mandatory=$true)] | |
[String[]] $Computer, | |
[Parameter(Mandatory=$true)] | |
[String] $ShareName, | |
[Parameter(Mandatory=$true)] | |
[String] $FolderName, | |
[Parameter(Mandatory=$true)] | |
[String] $ClientFilter, | |
[Parameter(Mandatory=$true)] | |
[String] $FilterMode, | |
[Parameter(Mandatory=$true)] | |
[String] $SourceScriptPath, | |
[Parameter(Mandatory=$true)] | |
[String] $ConfigurationFolder, | |
[Parameter(Mandatory=$true)] | |
[String] $OriginConfigurationFolder, | |
[Parameter(Mandatory=$true)] | |
[String] $ScriptFolder, | |
[Parameter(Mandatory=$true)] | |
[int] $ConfigurationModeFrequencyMins, | |
[Parameter(Mandatory=$true)] | |
[int] $RefreshFrequencyMins | |
) | |
#Define path of configuration file generated by administrator | |
$OriginConfigurationPath = "\\$PullServer\$PullShare\$OriginConfigurationFolder\" | |
<#Define path of configuration file auto generated (by configuration on pull server). | |
This files is with a guid name and there is a checksum file for each configuration file.#> | |
$ConfigurationPath = "\\$PullServer\$PullShare\$ConfigurationFolder\" | |
#Define | |
$DestinationScriptPath = "\\$PullServer\$PullShare\$ScriptFolder\" | |
#Pull server configuration will be generated for a computer | |
Node $Computer { | |
<#Script ressource to create folder for the share that contains all configurations files (ComputerName.mof, GUID.mof, | |
GUID.mof.checksum and ComputerName.meta.mof) and library's scripts #> | |
Script CreateFolderShare { | |
#Set folder share | |
SetScript = $([string]{ | |
#Create folder | |
New-Item $FolderName -ItemType Directory | |
}).Replace('$FolderName',"'$FolderName'") | |
#Test folder existence (return boolean, dsc script ressource pre requisites) | |
TestScript = $([string]{ | |
try{ | |
Get-Item $FolderName -ErrorAction Stop | |
return $true | |
}catch{ | |
return $false | |
} | |
}).Replace('$FolderName',"'$FolderName'") | |
#Retrieve script configuration. Return hashtable (dsc script ressource pre requisites). | |
GetScript = $([string]{ | |
$Result = "" | |
try{ | |
$Test = Get-Item $FolderName -ErrorAction Stop | |
$Result = "$FolderName for Pull Server exist." | |
}catch{ | |
$Result = "$FolderName for Pull Server doesn't exist." | |
} | |
return @{ | |
GetScript = $GetScript | |
SetScript = $SetScript | |
TestScript = $TestScript | |
Result = $Result | |
}}).Replace('$FolderName',"'$FolderName'") | |
} | |
<#Script ressource to add NTFS permissions on Pull SMB folder. Everyone must have read and execute right and Pull server computer | |
account must have full control right.#> | |
Script AddNTFSPermission { | |
#Depends on CreateFolderShare ressource | |
DependsOn = "[Script]CreateFolderShare" | |
#Add read and execute permission for everyone group and full control for the pull server computer account | |
SetScript = $([string]{ | |
#Retrieve everyone group SID | |
$Sid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::WorldSid, $null) | |
#Get ACL on Pull server SMB folder | |
$ACL = Get-Acl -Path $FolderName | |
#Create permission for everyone group | |
$Permission = $Sid,"ReadAndExecute","ContainerInherit,ObjectInherit","None","Allow" | |
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $Permission | |
#Add ACL on ACL list | |
$ACL.SetAccessRule($AccessRule) | |
#Get computer account | |
$User = New-Object System.Security.Principal.NTAccount(($env:userdomain+"\"+$PullServer+"$")) | |
$StrSID = $User.Translate([System.Security.Principal.SecurityIdentifier]) | |
#Retrieve Sid | |
$Sid = New-Object security.principal.securityidentifier($StrSID) | |
#Create permission for computer account | |
$Permission = $Sid,"FullControl","ContainerInherit,ObjectInherit","None","Allow" | |
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $Permission | |
#Add ACL on ACL list | |
$ACL.SetAccessRule($AccessRule) | |
#Set ACL list on folder | |
$ACL | Set-Acl $FolderName | |
}).Replace('$FolderName',"'$FolderName'").Replace('$PullServer',"'$PullServer'") | |
#Test existence of read and execute permission for everyone group and full control for the pull server computer account | |
TestScript = $([string]{ | |
#If error when retrieving permissions, result is false | |
try{ | |
#Get ACL for everyone group | |
$ACLEveryone = (Get-Acl -Path $FolderName -ErrorAction Stop).Access | ` | |
Where-Object {($_.FileSystemRights -like '*ReadAndExecute*') ` | |
-and ($_.AccessControlType -eq 'Allow') -and ` | |
($_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) -eq ` | |
(New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::WorldSid, $null)))} | |
#Get user | |
$User = New-Object System.Security.Principal.NTAccount(($env:userdomain+"\"+$PullServer+"$")) | |
$StrSID = $User.Translate([System.Security.Principal.SecurityIdentifier]) | |
#Retrieve Sid | |
$Sid = New-Object security.principal.securityidentifier($StrSID) | |
#Get ACL for computer account | |
$ACLComputer = (Get-Acl -Path $FolderName -ErrorAction Stop).Access | ` | |
Where-Object {($_.FileSystemRights -like '*FullControl*') ` | |
-and ($_.AccessControlType -eq 'Allow') -and ` | |
($_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) -eq $Sid)} | |
}catch{ | |
return $false | |
} | |
#If permission has been found result is true, otherwise result is false | |
if(($ACLEveryone.count -gt 0) -and ($ACLComputer.count -gt 0)){ | |
return $true | |
}else{ | |
return $false | |
} | |
}).Replace('$FolderName',"'$FolderName'").Replace('$PullServer',"'$PullServer'") | |
#Get script configuration and retrieve result about NTFS permission on pull server SMB folder (return hashtable). | |
GetScript = $([string]{ | |
$Result = "" | |
try{ | |
#Get ACL for everyone group | |
$ACLEveryone = (Get-Acl -Path $FolderName -ErrorAction Stop).Access | ` | |
Where-Object {($_.FileSystemRights -like '*ReadAndExecute*') ` | |
-and ($_.AccessControlType -eq 'Allow') -and ` | |
($_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) -eq ` | |
(New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::WorldSid, $null)))} | |
#Get user | |
$User = New-Object System.Security.Principal.NTAccount(($env:userdomain+"\"+$PullServer+"$")) | |
$StrSID = $User.Translate([System.Security.Principal.SecurityIdentifier]) | |
#Retrieve Sid | |
$Sid = New-Object security.principal.securityidentifier($StrSID) | |
#Get ACL for computer account | |
$ACLComputer = (Get-Acl -Path $FolderName -ErrorAction Stop).Access | ` | |
Where-Object {($_.FileSystemRights -like '*FullControl*') ` | |
-and ($_.AccessControlType -eq 'Allow') -and ` | |
($_.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]) -eq $Sid)} | |
}catch{ | |
$Result = "Error on retrieving ACL. " | |
} | |
#Result is successfull if permission has been found for everyone group | |
if($ACLEveryone.count -gt 0){ | |
$Result = "Everyone ReadAndExecute ACL has been found on $FolderName. " | |
}else{ | |
$Result = "No Everyone ReadAndExecute ACL has been retrieve on $FolderName. " | |
} | |
#Result is successfull if permission has been found for computer account | |
if($ACLComputer.count -gt 0){ | |
$Result += "$PullServer`$ FullControl ACL has been found on $FolderName. " | |
}else{ | |
$Result += "No $PullServer`$ FullControl ACL has been retrieve on $FolderName. " | |
} | |
return @{ | |
GetScript = $GetScript | |
SetScript = $SetScript | |
TestScript = $TestScript | |
Result = $Result | |
}}).Replace('$FolderName',$FolderName).Replace('$PullServer',"'$PullServer'") | |
} | |
<#Script ressource to create share on Pull server (locally) that contains all configurations files (ComputerName.mof, GUID.mof, | |
GUID.mof.checksum and ComputerName.meta.mof) and library's scripts. This share will add permission to read and execute for | |
everyone builtin group and Full access to the pull server computer account#> | |
Script AddShare { | |
#This ressource depends on folder existence (it won't be executed if folder doesn't exist). | |
DependsOn = "[Script]AddNTFSPermission" | |
#Create share with permissions | |
SetScript = $([string]{ | |
$ShareExist = Get-WmiObject Win32_Share -filter “name=$ShareName” -ErrorAction Stop | |
If($ShareExist -ne $null){ | |
$ShareExist.InvokeMethod("Delete",$null) | |
} | |
#Retrieve SID for everyone group (this method bypass operating system culture) | |
$Sid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::WorldSid, $null) | |
[byte[]]$Ba = ,0 * $Sid.BinaryLength | |
[void]$Sid.GetBinaryForm($ba,0) | |
#Create trustee (user that will have a permission) | |
$Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() | |
#Set sid | |
$Trustee.SID = $Ba | |
#Create ACE | |
$Ace = ([WMIClass] "Win32_ace").CreateInstance() | |
#Define right | |
$Ace.AccessMask = [System.Security.AccessControl.FileSystemRights] "Full" | |
$Ace.AceFlags = 0 | |
$Ace.AceType = 0 | |
#Define user in ACE | |
$Ace.Trustee = $trustee | |
#Create Security Descriptor containing ACE | |
$Sd = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() | |
$Sd.DACL += @($Ace.psobject.baseobject) | |
$Sd.ControlFlags="0x4" | |
#Wmi class share instance | |
$Shares=[wmiclass]”WIN32_Share” | |
#Create pull share with local path, share name and permissions (in a security descriptor) | |
try{ | |
$Shares.Create($FolderName,$ShareName,0,$null,$null,$null,$Sd) | |
}catch{ | |
Write-Host "Error during creation of pull share." | |
} | |
}).Replace('$FolderName',"'$FolderName'").Replace('$ShareName',"'$ShareName'") | |
#Test share existence and permissions (return boolean) | |
TestScript = $([string]{ | |
#Retrieve pull share and her local path | |
$ShareExist = Get-WmiObject Win32_Share -filter “name=$ShareName” -ErrorAction Stop | |
If(($ShareExist -eq $null) -or ($ShareExist.Path -ne $FolderName)){ | |
return $false | |
} | |
#Get share permissions by retrieving security settings | |
$SharedSecs = Get-WmiObject -Class Win32_LogicalShareSecuritySetting -Filter "Name=$ShareName" | |
#Get security descriptor associated to security settings | |
$SecDescriptor = $SharedSecs.GetSecurityDescriptor() | |
#Array containing all effective permissions | |
$EffectiveACLList = @() | |
#For each DACL | |
foreach($DACL in $SecDescriptor.Descriptor.DACL) | |
{ | |
#Retrieve username | |
$UserName = $DACL.Trustee.Name | |
#Get right | |
$Access = $DACL.AccessMask | |
#Create psobject with right and user | |
$Obj = New-Object psobject | |
$ACL = $Obj | Select-Object Access, User | |
$ACL.Access = $Access | |
$ACL.User = $UserName | |
#Add psobject to array | |
$EffectiveACLList += $ACL | |
} | |
#Retrieve Everyone account | |
$Sid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::WorldSid, $null) | |
$Everyone = ($Sid.Translate([System.Security.Principal.NTAccount])).Value | |
#Try to find them in effective permissions | |
$ValidACL = $EffectiveACLList | Where-Object {($_.User -eq $Everyone) -and ($_.Access -eq "2032127")} | |
#If permission is not present, return false | |
if(!$ValidACL){ | |
return $false | |
} | |
return $true | |
}).Replace('$FolderName',"'$FolderName'").Replace('$ShareName',"'$ShareName'") | |
#Get share configuration (return hastable). Structure is similar to TestScript. Only return change (string instead of boolean) | |
GetScript = $([string]{ | |
#Retrieve pull share | |
$ShareExist = Get-WmiObject Win32_Share -filter “name=$ShareName” -ErrorAction Stop | |
If($ShareExist -ne $null){ | |
$Result = "Pull Server share is $ShareName. " | |
}else{ | |
$Result = "Pull Server share $ShareName doesn't exist. " | |
return @{GetScript = $GetScript; SetScript = $SetScript; TestScript = $TestScript; Result = $Result} | |
} | |
#Retrieve local path for pull share | |
If($ShareExist.Path -eq $FolderName){ | |
$Result += "Pull Server local path is $FolderName. " | |
}else{ | |
$Result += "Pull Server local path is not (" + $ShareExist.path + "). " | |
return @{GetScript = $GetScript; SetScript = $SetScript; TestScript = $TestScript; Result = $Result} | |
} | |
#Get share permissions by retrieving security settings | |
$SharedSecs = Get-WmiObject -Class Win32_LogicalShareSecuritySetting -Filter "Name=$ShareName" | |
#Get security descriptor associated to security settings | |
$SecDescriptor = $SharedSecs.GetSecurityDescriptor() | |
#Array containing all effective permissions | |
$EffectiveACLList = @() | |
foreach($DACL in $SecDescriptor.Descriptor.DACL) | |
{ | |
#Retrieve username | |
$UserName = $DACL.Trustee.Name | |
#Get right | |
$Access = $DACL.AccessMask | |
#Create psobject with right and user | |
$Obj = New-Object psobject | |
$ACL = $Obj | Select-Object Access, User | |
$ACL.Access = $Access | |
$ACL.User = $UserName | |
#Add psobject to array | |
$EffectiveACLList += $ACL | |
} | |
#Variable to check for error | |
$TestValidPermissions = $true | |
#Retrieve Everyone account | |
$Sid = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::WorldSid, $null) | |
$Everyone = ($Sid.Translate([System.Security.Principal.NTAccount])).Value | |
#Try to find them in effective permissions | |
$ValidACL = $EffectiveACLList | Where-Object {($_.User -eq $Everyone) -and ($_.Access -eq "2032127")} | |
#If permission is not present, return false | |
if(!$ValidACL){ | |
$Result += "Share permissions is not valid for " + $Everyone + ". " | |
$TestValidPermissions = $false | |
} | |
#if no error has been found | |
if($TestValidPermissions){ | |
$Result += "All permissions is correctly set on Pull server share." | |
} | |
return @{ | |
GetScript = $GetScript | |
SetScript = $SetScript | |
TestScript = $TestScript | |
Result = $Result | |
}}).Replace('$FolderName',"'$FolderName'").Replace('$ShareName',"'$ShareName'") | |
} | |
<#Script ressource. It creates folder tree in pull share. 3 folders will be created in this script : | |
- a folder that contains configuration file generated by user | |
- a folder that contains Powershell functions. These functions will be used to generate LocalConfigurationManagerFile | |
- a folder that contains configuration with a guid in filename and a checksum file (these files will be auto generated) | |
#> | |
Script CreateFolderTree { | |
#This ressource depends on pull share creation | |
DependsOn = "[Script]AddShare" | |
#Create folder | |
SetScript = $([string]{ | |
#Array containing all folder share | |
$ListFolder = @($ConfigurationFolder, $OriginConfigurationFolder, $ScriptFolder) | |
#Create each folder in pull server share | |
ForEach($Folder in $ListFolder){ | |
New-Item -Path ("\\" + $PullServer + "\" + $ShareName + "\" + $Folder) -ItemType Directory -Force | |
} | |
}).Replace('$ShareName',"'$ShareName'").Replace('$ConfigurationFolder',"'$ConfigurationFolder'").` | |
Replace('$ScriptFolder',"'$ScriptFolder'").Replace('$OriginConfigurationFolder',"'$OriginConfigurationFolder'").` | |
Replace('$PullServer',"'$PullServer'") | |
#Test folder existence (return boolean) | |
TestScript = $([string]{ | |
#Array containing all folder share | |
$ListFolder = @($ConfigurationFolder, $OriginConfigurationFolder, $ScriptFolder) | |
#Test existence of each folder in pull server share | |
ForEach($Folder in $ListFolder){ | |
try{ | |
Get-Item ("\\" + $PullServer + "\" + $ShareName + "\" + $Folder) -ErrorAction Stop | |
}catch{ | |
return $false | |
} | |
} | |
return $true | |
}).Replace('$ShareName',"'$ShareName'").Replace('$ConfigurationFolder',"'$ConfigurationFolder'").` | |
Replace('$ScriptFolder',"'$ScriptFolder'").Replace('$OriginConfigurationFolder',"'$OriginConfigurationFolder'").` | |
Replace('$PullServer',"'$PullServer'") | |
#Get folder hierarchy on pull share (return hashtable) | |
GetScript = $([string]{ | |
$Result = "" | |
#Array containing all folder share | |
$ListFolder = @($ConfigurationFolder, $OriginConfigurationFolder, $ScriptFolder) | |
ForEach($Folder in $ListFolder){ | |
try{ | |
#You must save result in a variable (or you will get an error) | |
$Item = Get-Item ("\\" + $PullServer + "\" + $ShareName + "\" + $Folder) -ErrorAction Stop | |
#Add string to result | |
$Result += "$Folder folder exists in \\" + $PullServer + "\" + $ShareName+". " | |
}catch{ | |
#Add string to result | |
$Result += "$Folder folder doesn't exists in \\" + $PullServer + "\" + $ShareName+". " | |
} | |
} | |
return @{ | |
GetScript = $GetScript | |
SetScript = $SetScript | |
TestScript = $TestScript | |
Result = $Result | |
}}).Replace('$ShareName',"'$ShareName'").Replace('$ConfigurationFolder',"'$ConfigurationFolder'").` | |
Replace('$ScriptFolder',"'$ScriptFolder'").Replace('$OriginConfigurationFolder',"'$OriginConfigurationFolder'").` | |
Replace('$PullServer',"'$PullServer'") | |
} | |
<#File ressource that copy library functions (Library Pull Configuration.ps1), to generate LocalConfigurationManager | |
configuration, retrieve clients computers #> | |
File PullScripts{ | |
Ensure = "Present" | |
SourcePath = $SourceScriptPath | |
DestinationPath = $DestinationScriptPath | |
Recurse = $true | |
Type = "Directory" | |
DependsOn = "[Script]CreateFolderTree" | |
} | |
#Script ressource to generate LocalConfigurationManager file for clients computers. | |
Script GenerateLCM{ | |
#Depends on PullScripts ressource | |
DependsOn = "[File]PullScripts" | |
#Generate LocalConfigurationManager configuration for all computers in a group or organizational unit | |
SetScript = $([string]{ | |
#Load Library | |
. ($DestinationScriptPath+"\Library Pull Configuration.ps1") | |
#Define directory containing LocalConfigurationManager configuration file | |
$OutputPath = "\\"+$PullServer+"\"+$PullShare+"\LCM" | |
#Retrieve clients computer (see Library Pull Configuration.ps1 for description) | |
$Clients = Get-ClientComputer -SearchIn $FilterMode -Filter $ClientFilter | |
#Retrieve computers that doesn't have a LocalConfigurationManager configuration file | |
$Clients = $Clients | Where-Object {(Test-Path ($OutputPath+"\"+$_+".meta.mof")) -eq $false} | |
if($Clients -ne $null){ | |
#Create LocalConfigurationManager configuration file | |
(LocalConfigurationManager -OutputPath $OutputPath -Computers $Clients -PullServer $PullServer -PullShare $PullShare ` | |
-ConfigurationFolder $ConfigurationFolder -RefreshFrequencyMins $RefreshFrequencyMins -ConfigurationModeFrequencyMins $ConfigurationModeFrequencyMins) | |
} | |
}).Replace('$DestinationScriptPath',"'$DestinationScriptPath'").Replace('$FilterMode',"'$FilterMode'").` | |
Replace('$ClientFilter',"'$ClientFilter'").Replace('$PullShare',"'$PullShare'").Replace('$PullServer',"'$PullServer'").` | |
Replace('$ConfigurationFolder',"'$ConfigurationFolder'").Replace('$ConfigurationModeFrequencyMins',"'$ConfigurationModeFrequencyMins'").` | |
Replace('$RefreshFrequencyMins',"'$RefreshFrequencyMins'") | |
#Test presence of LocalConfigurationManager configuration file for specified computers (return boolean) | |
TestScript = $([string]{ | |
#Load Library | |
. ($DestinationScriptPath+"\Library Pull Configuration.ps1") | |
#Define directory containing LocalConfigurationManager configuration file | |
$OutputPath = "\\"+$PullServer+"\"+$PullShare+"\LCM" | |
#Retrieve clients computer (see Library Pull Configuration.ps1 for description) | |
$Clients = Get-ClientComputer -SearchIn $FilterMode -Filter $ClientFilter | |
#Retrieve computers that doesn't have a LocalConfigurationManager configuration file | |
$Clients = $Clients | Where-Object {(Test-Path ($OutputPath+"\"+$_+".meta.mof")) -eq $false} | |
#If all client have a LocalConfigurationManager configuration file return true | |
if($Clients -eq $null){ | |
return $true | |
}else{ | |
return $false | |
} | |
}).Replace('$DestinationScriptPath',"'$DestinationScriptPath'").Replace('$FilterMode',"'$FilterMode'").` | |
Replace('$ClientFilter',"'$ClientFilter'").Replace('$PullShare',"'$PullShare'").Replace('$PullServer',"'$PullServer'").` | |
Replace('$ConfigurationFolder',"'$ConfigurationFolder'") | |
#Retrieve presence LocalConfigurationManager configuration files in a human readable result (return hashtable) | |
GetScript = $([string]{ | |
#Load Library | |
. ($DestinationScriptPath+"\Library Pull Configuration.ps1") | |
#Define directory containing LocalConfigurationManager configuration file | |
$OutputPath = "\\"+$PullServer+"\"+$PullShare+"\LCM" | |
#Retrieve clients computer (see Library Pull Configuration.ps1 for description) | |
$Clients = Get-ClientComputer -SearchIn $FilterMode -Filter $ClientFilter | |
if($Clients -eq $null){ | |
$Result = "There isn't clients in $ClientFilter $FilterMode. No configuration has been generated." | |
} | |
#Retrieve computers that doesn't have a LocalConfigurationManager configuration file | |
$ClientsNotValid = $Clients | Where-Object {(Test-Path ($OutputPath+"\"+$_+".meta.mof")) -eq $false} | |
#If all client have a LocalConfigurationManager configuration file return true | |
if($ClientsNotValid -eq $null){ | |
$Result = "All clients in $ClientFilter $FilterMode have a valid configuration." | |
}else{ | |
$Result = $ClientsNotValid -join "," | |
$Result += " hasn't LocalConfigurationManager (.meta.mof) file." | |
} | |
return @{ | |
GetScript = $GetScript | |
SetScript = $SetScript | |
TestScript = $TestScript | |
Result = $Result | |
}}).Replace('$DestinationScriptPath',"'$DestinationScriptPath'").Replace('$FilterMode',"'$FilterMode'").` | |
Replace('$ClientFilter',"'$ClientFilter'").Replace('$PullShare',"'$PullShare'").Replace('$PullServer',"'$PullServer'").` | |
Replace('$ConfigurationFolder',"'$ConfigurationFolder'") | |
} | |
<#Script ressource to auto update configuration file. Retrieve files in $OriginConfiguration folder on pull server share. | |
Copy theses files in $ConfigurationFolder to permit clients to get her configuration. In $ConfigurationFolder, each file | |
will be rename with the GUID of the computer and a checksum file will be generated. When copying a file, if it already exists, | |
the script compares the hash and overwrite the file in $DestinationFolder if the hash is different.#> | |
Script AutoUpdateConfiguration{ | |
#This ressurce depends on PullScripts ressource | |
DependsOn = "[File]PullScripts" | |
#Generate new configuration files for pull clients | |
SetScript = $([string]{ | |
#Load Library | |
. ($DestinationScriptPath+"\Library Pull Configuration.ps1") | |
#Retrieve clients computer (see Library Pull Configuration.ps1 for description) | |
$Clients = Get-ClientComputer -SearchIn $FilterMode -Filter $ClientFilter | |
#Retrieve clients computers having a configuration file in $OriginConfiguration folder | |
$Clients = $Clients | Where-Object {(Test-Path ($OriginConfigurationPath+"\"+$_+".mof")) -eq $true} | |
#ForEach client that has been retrieved | |
ForEach($Client in $Clients){ | |
#Get computer GUID (see Library Pull Configuration.ps1 for description) | |
$GUID = Get-ComputerGuid $Client | |
#Define configuration file path with a guid | |
$FileConfig = $ConfigurationPath+"\"+$GUID+".mof" | |
#Define full path of configuration file generated by an administrator | |
$OriginConfiguration = $OriginConfigurationPath+"\"+$Client+".mof" | |
#If file with a GUID is not present then copy the file and create a checksum | |
if(!(Test-Path $FileConfig)){ | |
Copy-Item -Path $OriginConfiguration -Destination $FileConfig | |
New-FileChecksum -FilePath $FileConfig | |
}else{ | |
#If file already exists, retrieve the hash of each file | |
$FileHashConfig = (Get-FileHash $OriginConfiguration).hash | |
$FileHashOriginConfig = [String](Get-Content ($FileConfig+".checksum")) | |
#If these 2 hash is different then overwrite the configuration file with a GUID and regenrate a checksum file | |
if($FileHashConfig -ne $FileHashOriginConfig){ | |
Copy-Item -Path $OriginConfiguration -Destination $FileConfig | |
New-FileChecksum -FilePath $FileConfig | |
} | |
} | |
} | |
}).Replace('$DestinationScriptPath',"'$DestinationScriptPath'").Replace('$FilterMode',"'$FilterMode'").` | |
Replace('$ClientFilter',"'$ClientFilter'").Replace('$ConfigurationPath',"'$ConfigurationPath'").Replace('$PullServer',"'$PullServer'").` | |
Replace('$OriginConfigurationPath',"'$OriginConfigurationPath'") | |
#Test if updated configuration file for clients is present (for configuration that has been created by an administrator) | |
TestScript = $([string]{ | |
#Load Library | |
. ($DestinationScriptPath+"\Library Pull Configuration.ps1") | |
#Retrieve clients computer (see Library Pull Configuration.ps1 for description) | |
$Clients = Get-ClientComputer -SearchIn $FilterMode -Filter $ClientFilter | |
#Retrieve clients computers having a configuration file in $OriginConfiguration folder | |
$Clients = $Clients | Where-Object {(Test-Path ($OriginConfigurationPath+"\"+$_+".mof")) -eq $true} | |
#Test variable (test result is OK as long as variable is not changed) | |
$Test = $true | |
#ForEach client that has been retrieved | |
ForEach($Client in $Clients){ | |
#Get computer GUID (see Library Pull Configuration.ps1 for description) | |
$GUID = Get-ComputerGuid $Client | |
#Define configuration file path with a guid | |
$FileConfig = $ConfigurationPath+"\"+$GUID+".mof" | |
#Define full path of configuration file generated by an administrator | |
$OriginConfiguration = $OriginConfigurationPath+"\"+$Client+".mof" | |
#If file with a GUID is not present for one client, the test is failed | |
if(!(Test-Path $FileConfig)){ | |
$Test = $false | |
break; | |
}else{ | |
#If file already exists, retrieve the hash of each file | |
$FileHashConfig = (Get-FileHash $OriginConfiguration).hash | |
$FileHashOriginConfig = [String](Get-Content ($FileConfig+".checksum")) | |
#If these 2 hash is different, the test is failed | |
if($FileHashConfig -ne $FileHashOriginConfig){ | |
$Test = $false | |
break; | |
} | |
} | |
} | |
return $Test | |
}).Replace('$DestinationScriptPath',"'$DestinationScriptPath'").Replace('$FilterMode',"'$FilterMode'").` | |
Replace('$ClientFilter',"'$ClientFilter'").Replace('$ConfigurationPath',"'$ConfigurationPath'").Replace('$PullServer',"'$PullServer'").` | |
Replace('$OriginConfigurationPath',"'$OriginConfigurationPath'") | |
GetScript = $([string]{ | |
#Load Library | |
. ($DestinationScriptPath+"\Library Pull Configuration.ps1") | |
#Retrieve clients computer (see Library Pull Configuration.ps1 for description) | |
$Clients = Get-ClientComputer -SearchIn $FilterMode -Filter $ClientFilter | |
#Retrieve clients computers having a configuration file in $OriginConfiguration folder | |
$Clients = $Clients | Where-Object {(Test-Path ($OriginConfigurationPath+"\"+$_+".mof")) -eq $true} | |
#Result variable | |
$Result = "" | |
#ForEach client that has been retrieved | |
ForEach($Client in $Clients){ | |
#Get computer GUID (see Library Pull Configuration.ps1 for description) | |
$GUID = Get-ComputerGuid $Client | |
#Define configuration file path with a guid | |
$FileConfig = $ConfigurationPath+"\"+$GUID+".mof" | |
#Define full path of configuration file generated by an administrator | |
$OriginConfiguration = $OriginConfigurationPath+"\"+$Client+".mof" | |
#If file with a GUID is not present for one client | |
if(!(Test-Path $FileConfig)){ | |
$Result += "$Client has no configuration file. " | |
}else{ | |
#If file already exists, retrieve the hash of each file | |
$FileHashConfig = (Get-FileHash $OriginConfiguration).hash | |
$FileHashOriginConfig = [String](Get-Content ($FileConfig+".checksum")) | |
#If these 2 hash is different, the client has an invalid configuration file | |
if($FileHashConfig -ne $FileHashOriginConfig){ | |
$Result += "$Client has an invalid configuration file (difference with file in $OriginConfigurationPath). " | |
} | |
} | |
} | |
#If result has not been modified, then all configuration files is valid. | |
if($Result -eq ""){ | |
$Result = "All configuration files is valid." | |
} | |
return @{ | |
GetScript = $GetScript | |
SetScript = $SetScript | |
TestScript = $TestScript | |
Result = $Result | |
}}).Replace('$DestinationScriptPath',"'$DestinationScriptPath'").Replace('$FilterMode',"'$FilterMode'").` | |
Replace('$ClientFilter',"'$ClientFilter'").Replace('$ConfigurationPath',"'$ConfigurationPath'").Replace('$PullServer',"'$PullServer'").` | |
Replace('$OriginConfigurationPath',"'$OriginConfigurationPath'") | |
} | |
} | |
} | |
################################################################## | |
# Variables # | |
################################################################## | |
#Pull server name | |
$PullServer = "$env:Computername" | |
#Pull server share | |
$PullShare = "PullDSC" | |
#Pull server path | |
$MOFFolder = "C:\TESTDSC" | |
#Pull clients filter (organizational unit or AD group) | |
$FilterMode = "OU" | |
#Pull clients filter name (name of an organizational unit ou AD group) in minutes | |
$ClientFilter = "12FS" | |
#Frequency between two configuration check in minutes | |
$ConfigurationModeFrequencyMins = 75 | |
#Frequency between two refresh of the configuration fil | |
$RefreshFrequencyMins = 30 | |
<#Folder containing configuration file (MOF) on pull share (containing MOF file with GUID in name and checksum files). | |
Theses files are auto generated by configuration #> | |
$ConfigurationFolder = "Configuration" | |
#Folder containing original configuration file (MOF) on pull share that user can modify. | |
$OriginConfigurationFolder = "OriginalConfiguration" | |
#Folder containing functions on pull share (Library Pull Configuration.ps1). The file will be retrieve and use by the DSC configuration. | |
$ScriptFolder = "Scripts" | |
#Retrieve script execution path | |
$RootFolder = Split-Path -Path $MyInvocation.MyCommand.Path | |
#Folder path containing script (Library Pull Configuration.ps1) that will be retrieve by DSC file ressource on pull server. | |
$SourceScriptPath = "$RootFolder\$ScriptFolder\" | |
################################################################## | |
# Main # | |
################################################################## | |
#Generate configuration file for DSC pull server (smb) | |
DSCPullServer -Computer $PullServer -FolderName $MOFFolder -ShareName $PullShare -ClientFilter $ClientFilter ` | |
-FilterMode $FilterMode -SourceScriptPath $SourceScriptPath -ConfigurationFolder $ConfigurationFolder ` | |
-ConfigurationModeFrequencyMins $ConfigurationModeFrequencyMins -RefreshFrequencyMins $RefreshFrequencyMins ` | |
-OriginConfigurationFolder $OriginConfigurationFolder -ScriptFolder $ScriptFolder -OutputPath C:\PSDSC | |
#Configure DSC pull server | |
Start-DscConfiguration "C:\PSDSC" -ComputerName $PullServer -Wait -Verbose | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment