Client management in the domain using PowerShell
On My Mark
Tools such as System Center Configuration Manager, opsi-winst, or Puppet offer client management, but the learning curve can be huge. Instead, a flexible combination of DIY scripts and a simple storage solution offers a perfect solution. In this article, I automate various client management tasks in a domain with PowerShell with a focus on the following areas:
- Printer management.
- Checking for installation of certain Windows features.
- Listing a computer's group memberships.
- Entering DNS servers.
I am using Windows 10 client with a Windows Server 2012 R2 domain, with PowerShell v5 on the client and PowerShell v4 on the server.
Administration via a CSV File
In PowerShell remoting, a distinction is made between 1:1 and 1:n (fan-out) relationships. 1:1 remote management is implemented through the PsSession
concept. Fan-out remote management – that is, simultaneous processing of instructions on multiple target computers – is achieved through invoke-Command
and its parameters. In this process, separating the configuration settings from the programming logic is useful for maintaining the script. The data can be stored in a database, or an XML or text file.
In particular, a structured, comma-separated values (CSV) file provides a simple and practical approach. It is easily maintained – even for administrators with less scripting experience. The columns in the CSV table include the IP address of the Windows client, the DNS servers, desired Windows features, printers, required group memberships, and optionally other control information. The script is executed remotely via a central management computer. This eliminates the need for time-consuming local modification of individual clients. On running the script, you may need to pass in the required authorization context via the -Credential
parameter. In addition to PowerShell cmdlets and Windows Management Instrumentation (WMI), you also use classes from the System.Directory.DirectoryService
namespace for processing.
Before the automated configuration begins, you need to import the value store. The Import-Csv -Path
path to the CSV file gives you hash-value table. The defined column names act as indexes for accessing the values. A foreach
loop iterates through the rows. For each line, this returns the intermediate variables $Item.IP
, $Item.DNS
, $item.FEATURE,Item.GROUPS
, and Item.PRINTERS
. For simplicity's sake, I will be outputting individual values for each column in this article. When saving multiple values per column, it is a good idea to choose a delimiter that differs from the selected column separator. The pipe character |
is a good choice. The field can be broken down and processed with the string operation $item.columnname.split("|")
.
This information needs to be put in the context of the processing functions. However, to configure the client, you first need working network connectivity. For this reason, the first auxiliary function checks the availability of the computer and quits with an exit code if it is not given. The use of ping.exe
is not effective. Its output, in the form of a string, depends on the language version, which makes the analysis tricky. It is far better to use:
test-Connection -ComputerName -ComputerName Item.IP
The output takes the form of a unique Boolean type ($TRUE
, $FALSE
):
if (test-Connection -ComputerName -ComputerName Item.IP){..}else{exit 1}"
Establishing Trust
If your company uses a directory service, you also need other data besides the client's IP address. Therefore, auxiliary functions determine the host-specific variables from the IP address. Remote access to the client using
invoke-Command -ScriptBlock {...} -credential $cred -ComputerName Item.IP
needs some preliminary work. After all, PowerShell remoting is based on mutual authentication. This is possible via the client, but not via the IP address. If you want PowerShell to trust the remote site, you need to enter the IP addresses of all the target computers in the Trusted Hosts field up front:
Set-Item WSMAN:\localhost\Client\TrustedHosts IP,IP2,etc
Determining the fully qualified domain name (FQDN) is not as trivial as it first appears. In one approach, the environment variables are mapped in the corresponding PsDrive ENV:
. However, a combination of $env:ComputerName
and $env:UserDomain
does not make sense. The variable ComputerName
contains the NetBIOS name, and UserDomain
is filled with the local computer name except when the user is logged into a domain. These are two key limitations that you have to deal with. However, you can use the FQDN to determine the actual computer name and the domain with the following operations:
$Field = $FQDN.Split("."); $LDAPName = "cn=" + $Field[0]; $SimpleName = $Field[0]
Based on these values, you can start with the further processing steps. If the client is not a member of the domain, you can add it:
Add-Computer -DomainName MyDom.com -Credential Administrator@MyDom.com
Printer Management
Printer management is essentially the premise of WMI and the parent Common Information Model (CIM) classes up to PowerShell v4. Executability is not restricted by any PowerShell version (see Listing 1).
Listing 1
Printer management executability
$Drucker = "HP DeskJet 840C/841C/842C/843C" $ObjWMI = get-WmiObject -class Win32_Printer -Filter "name = '$drucker'"; $status = $ObjWMI.Printer.Status switch ($status) { "3" {"Printer is ready"} "4" {Printer working"} "5" {"Printer starting up"} "6" {"Print job finished"} "7" {"Printer is offline"} Default {"Unknown status"} }
As of PowerShell v4, there are command families for printer management, grouped around three central nouns: Printer
for access to local and network printers, Print Job
to control print jobs, and Printer Driver
for providing the required drivers as the basis for further printer management. However, administrative permissions must exist for providing the printer driver. Your task is to add a local printer driver. The add-printer driver
cmdlet needs the name of the printer driver; the full command is:
Add-PrinterDriver -Name "Drivername" -ComputerName "Client"
You must pass in the name of the driver accurately, including any spaces; otherwise the instruction will just provoke an error message. The use of wildcards is not allowed, such as passing in ranges with [d-g]
or using placeholders such as *
. The get-Printerdriver
cmdlet lists the available drivers.
If you need information, there is no alternative to creating an object, such as:
$Pr_DEf = (Get-Printer | ? {$_.Name -eq "MyPrinter"}); $Pr_DEf | Select-Object -Property Status, DriverName, Shared;
If you want this printer to be the default printer, choosing the WMI Win32_Printer
class makes sense:
$Ac_PR = gwmi win32_printer -Filter "name =MyPrinter"; $Ac_PR.setDefaultPrinter();
Buy this article as PDF
(incl. VAT)