How to set up and verify a Windows PowerShell DSC pull server in a lab deployment

(Update Completed)

This post contains some general steps for setting up a Windows PowerShell DSC pull server. It’s a quick note for myself, so it doesn’t show all the detail steps, you must read PowerShell team’s blog posts and community blog posts first. If you want to ask some questions, please leave a comment. Or if you want to blame me because this post does not help you to set up a pull server, please also leave a comment. :)

My lab contains 6 VMs, 1 domain controller and 5 utility servers. For a DSC pull server test lab, 4 VMs are involved. FAB-DC-01 is a domain controller. FAB-UTIL-07 is a DSC pull server. FAB-UTIL-08 and FAB-UTIL-09 are utility servers that will pull desired configuration from FAB-UTIL-01.

image

Steps:

(Thanks to PSRemoting, all the scripts are running on FAB-UTIL-01.)

  1. Download xPSDesiredStateConfiguration Module – PowerShell DSC Resource Kit from TechNet gallery. For the detail instruction, please refer to Reference 1. Then set up a pull server by using this module on FAB-UTIL-01. Finally, verify  the websites are working properly.
  2. Set up FAB-UTIL-08 and FAB-UTIL-09 by running Set-DscLocalConfigurationManager. See code block 1 for the script sample, please modify it before running in your lab. I follow Johan’s suggestion by using the objectGuid of one domain computer as the ConfigurationID.  (See code block 1)
  3. Use DSC configuration keyword and built-in resource, like Service to configure DSC pull client, FAB-UTIL-08 and FAB-UTIL-09. (See code block 2)
  4. Start scheduled task on FAB-UTIL-08 and FAB-UTIL-09. (See code block 3)
  5. Collect DSC events from event logs. (See code block 4)
  6. Write and test your own DSC custom resource. Here I write a WinHTTPProxy resource.
  7. When your DSC custom resource is ready, compress it to a zipped file. Then rename the zipped file to append a version number, like xWinHTTPProxy_1.0.zip.
  8. Run New-DSCCheckSum to create a checksum file for your DSC custom resource.
  9. Copy these two files to this folder %programfiles%\WindowsPowerShell\DscService\Modules.
  10. Use DSC configuration keyword and your custom resource, like xWinHTTPProxy to configure DSC pull client, FAB-UTIL-08 and FAB-UTIL-09. (See code block 5)
  11. Start scheduled task on FAB-UTIL-08 and FAB-UTIL-09. (See code block 3)
  12. Collect DSC events from event logs. (See code block 4)

Code Block 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$pullSvrUri = "https://fab-util-01.fabrikam.com:8080/PSDSCPullServer.svc"
$nodes = @("FAB-UTIL-08", "FAB-UTIL-09")

Configuration SetupDSCClient
{
    param ($Node, $PullServer, $ObjectGuid)

    Node $Node
    {
        LocalConfigurationManager
        {
            AllowModuleOverwrite = 'True'
            ConfigurationID = $ObjectGuid
            ConfigurationModeFrequencyMins = 30
            ConfigurationMode = 'ApplyAndAutoCorrect'
            RebootNodeIfNeeded = 'True'
            RefreshMode = 'Pull'
            RefreshFrequencyMins = 15
            DownloadManagerName = 'WebDownloadManager'
            DownloadManagerCustomData = (@{ServerUrl = $PullServer})
        }
    }
}

foreach ($node in $nodes)
{
    $objGuid = (Get-ADComputer -Identity $node).ObjectGuid.Guid.ToString()
    SetupDSCClient -Node $node -PullServer $pullSvrUri -ObjectGuid $objGuid -OutputPath $env:TEMP
}

Set-DscLocalConfigurationManager -ComputerName $nodes -Path $env:TEMP -Verbose

Code Block 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Configuration DNSCache
{
    param
    (
        [string[]]$Nodes
    )

    node ($Nodes)
    {
        Service DNSCache
        {
            Name  = "DNSCache"
            State = "Running"
        }
    }
}

$computers = "fab-util-08", "fab-util-09"
Get-ChildItem -Path 'C:\Program Files\WindowsPowerShell\DscService\Configuration\' | Remove-Item
foreach ($computer in $computers)
{
    $objGuid  = (Get-ADComputer -Identity $computer).ObjectGuid.Guid.ToString()
    $fileName = [System.String]::Concat($objGuid, ".mof")

    $mofFile = DNSCache -Node $computer -ObjectGuid $objGuid -OutputPath 'C:\Program Files\WindowsPowerShell\DscService\Configuration\'
    $newFile = Rename-Item -Path $mofFile.FullName -NewName $fileName -PassThru

    New-DSCCheckSum -ConfigurationPath $newFile.FullName -OutPath 'C:\Program Files\WindowsPowerShell\DscService\Configuration\'
}

Code Block 3

1
2
3
4
5
6
7
8
9
10
$computers = "fab-util-08", "fab-util-09"

foreach ($computer in $computers)
{
    $cimSession = New-CimSession -ComputerName $computer
   
    Get-ScheduledTask -TaskName "Consistency" -CimSession $cimSession | Start-ScheduledTask

    Remove-CimSession $cimSession
}

Code Block 4

1
2
3
4
5
6
7
$computers = "fab-util-08", "fab-util-09"

foreach ($computer in $computers)
{
    Get-WinEvent -LogName "Microsoft-Windows-Dsc/Operational" -ComputerName $computer -MaxEvents 5 | Select Message | fl *
    Write-Host "*******************" -ForegroundColor Green
}

Code Block 5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Configuration CompanyProxy
{
    param
    (
        [string[]]$Nodes
    )

    Import-DscResource -ModuleName xWinHttpProxy

    node ($Nodes)
    {
        xWinHttpProxy CompanyProxy
        {
            ProxyServer = "fab-util-01:1080"
            Ensure = "Present"
        }
    }
}

$computers = "fab-util-08", "fab-util-09"
Get-ChildItem -Path 'C:\Program Files\WindowsPowerShell\DscService\Configuration\' | Remove-Item
foreach ($computer in $computers)
{
    $objGuid  = (Get-ADComputer -Identity $computer).ObjectGuid.Guid.ToString()
    $fileName = [System.String]::Concat($objGuid, ".mof")

    $mofFile = CompanyProxy -Node $computer -ObjectGuid $objGuid -OutputPath 'C:\Program Files\WindowsPowerShell\DscService\Configuration\'
    $newFile = Rename-Item -Path $mofFile.FullName -NewName $fileName -PassThru

    New-DSCCheckSum -ConfigurationPath $newFile.FullName -OutPath 'C:\Program Files\WindowsPowerShell\DscService\Configuration\'
}

Screenshot for step 12.

PSDSC_PullServer

 

Acknowledgements:

Thanks Johan for the walkthrough.

References:

  1. http://blogs.msdn.com/b/powershell/archive/tags/desired+state+configuration/
  2. http://blog.cosmoskey.com/tag/pull-mode/

Windows Server 2012 RC 之 CIM cmdlets (01)

在Windows Server 2012发布后,首先再来看看Windows PowerShell 3.0中提供的新命令。这篇博文的目的是为了呼应Window PowerShell 产博客:Introduction to CIM Cmdlets。当然这里并不会全部翻译这篇博客,主要将结合我自己的理解做一些补充。

首先是一些名词之间的关系,大家已经从标题中看到了,今天将会涉及到的cmdlets是名词部分包含CIM的cmdlets。那么什么是CIM呢?CIM是由分布式管理任务组(DMTF)所制定的一个标准,用来描述受管理的诸如存储,网络或者软件组件的结构及行为。大家已经熟悉的WMI就是CIM在Windows中的实现。作为一款为云而优化的系统,Windows Server 2012中使用了防火墙友好型的WinRM协议(WS-Man协议的Windows实现),从而解决了之前由于使用DCOM而带来的诸多问题,同时也为支持WS-Man协议的异构系统实现了统一管理的可能。

接下来我们来看下名词部分包含CIM的cmdlets共有多少,获得这个列表的命令很简单,Get-Command -Noun CIM* 。

image

大家需要注意,名词包含CIM的cmdlets可以作为名词部分包含WMI的cmdlets的替代。因此还请大家从Windows Server 2012开始逐渐学会使用这些基础cmdlets,这些cmdlets将会为你打开Windows Server 2012的管理之门。

今天的这篇介绍主要集中在名词是CimSession的cmdlets。从之前的截图中大家已经看到了,一共是三项命令,New-CimSession,Get-CimSession和Remove-CimSession。

那么首先需要回答的问题是New-CimSession存在的意义,原来我们只需要直接使用Get-WMIObject即可,但为什么在Windows Server 2012中新增这个命令?最主要的理由是为了支持标准化,其次为了优化和远程计算机之间所产生的数据流量。为什么这么说,看过我之前博客的朋友可能依稀记得我曾说过每对远程计算机执行一次Get-WMIObject,都会打开和关闭一次网络会话,如果针对同一台服务器要查询多个类中的信息,那么带来的网络开销是非常可观的。而New-CIMSession的作用就是首先和远程服务器之间建立起一个会话通道,然后所有后续命令都通过这个通道来获得相应的数据。使用起来就是将New-CIMSession建立起来的会话保存到变量中,然后再在其它cmdlet中通过使用CIMSession参数来使用这个会话。

再举个形象点的例子,大家都喝过软包装饮料,建立CIMSession的作用就是将吸管插入,然后按需饮用,喝完之后将吸管拔出。而以前的做法就是喝一口就将吸管拔出,再喝的时候再次插入吸管,没人会这么做的吧?那么同样的,在Windows PowerShell V3之前ITPro可能没什么办法,在Windows PowerShell V3之后,还请大家养成建立CIMSession的习惯。

先来看看有多少cmdlet支持CIMSession参数:

image

可以看到有接近一半的cmdlet都支持CIMSession参数,这里我是通过安装RAST,然后导入所有可用模块来查找命令数量的,当然这个数量并不是非常精确的。接下来就是具体命令的比较,命令如下:

#1..10 | %{Get-WmiObject -ComputerName CNSHUTILSVR01 -Class Win32_Bios}

#1..10 | %{Get-CimInstance -ComputerName CNSHUTILSVR01 -Class Win32_Bios}

#$cimSession = New-CimSession -ComputerName cnshutilsvr01
#1..10 | %{Get-CimInstance -CimSession $cimSession -Class Win32_Bios}
#Remove-CimSession $cimSession

个中差异各位可以通过打开TCPView来进行比较:

image

名词部分是CIMSession的cmdlets都是比较容易使用的,这得益于PowerShell的统一和连贯的设计,相信大家使用下就能上手了,下次将介绍其它的和CIM有关的cmdlets,敬请期待。

快速更新: 享受升级到Windows Server 2012的乐趣

大家知道Windows Server 2012昨天正式发布了,然后进过一昼夜的下载,今天早上我下载完了ISO文件。然后晚上回家之后我迫不及待地开始升级工作了。

原先我有两台测试机,一台Windows Server 2012 RC,另一台是Windows Server 2008 R2,两台机器上一共有40台以上的虚拟机。然后由于之前已经阅读过产品组的相关文档,知道Hyper-V 3.0的导入功能异常强大,当系统崩溃然后重新安装完操作系统之后,只要提供相应的文件夹路径,Hyper-V 3.0就能导入这些文件。

于是我果断采取非常果敢的行动,直接重装操作系统,不做任何备份,然后结果正如产品组设计的那样。废话不多说了,直接上图:

image

image

图形界面中唯一不能做的是批量选取虚拟机,这应该是产品组决定交给PowerShell去解决了,稍后我会带来相关的截图。

总结起来一个字:

爽!

更新截图:

以下截图是在原先操作系统是Windows Server 2008 R2的测试机上截取的,最开始我直接尝试导入的时候提示导入失败,然后使用Compare-VM查找原因的时候发现是命令无法找到对应的虚拟交换机。

PS C:\> Get-ChildItem ‘D:\VMs\Virtual Machines’ *.xml | %{Compare-VM -Path $_.FullName} | Select-Object -ExpandPropertyIncompatibilities | FT -AutoSize

image

然后执行以下命令断开虚拟网卡,并尝试重新导入,该命令修改自Compare-VM中的示例。该命令仅在我的测试环境下进行测试,各位应根据自己的环境作出相应的调整。

PS C:\> Get-ChildItem ‘D:\VMs\Virtual Machines’ *.xml | %{$report = Compare-VM -Path $_.FullName; Disconnect-VMNetworkAdapter $report.Incompatibilities.Source -Verbose; Import-VM -CompatibilityReport $report -Verbose}

image

当然导入完成之后,需要重新配置虚拟机,但是相信这并不是一件挺麻烦的事,重要的是我们的虚拟机又能使用了,而且是在操作系统重装之后!

Windows Server 2012 RC 之 Hyper-V 3.0 PowerShell 命令详解 (04)

今天,我们接着对名词部分是VM的命令来一个巡礼。接下来要出场的是Move-VM,Move-VM的作用是将虚拟机从一台Hyper-V主机移动到另一台主机。如果已经玩过Hyper-V 3.0的朋友一定会被Hyper-V3.0中的移动功能所折服。就我个人而言,因为有时需要将虚拟机存储从SSD移动到西数黑盘上,这个功能是真心实用,向导也是简洁明了。

image

只是大家如果要使用PowerShell来完成移动任务的时候要注意,向导中的两种移动类型是由两个命令支持,分别是Move-VM和Move-VMStorage,今天先来谈谈Move-VM。

Move-VM一共有四个参数集,首先来看最简单的一个。这里还是以08R2-CNSHTSTSVR01这台机器作为示例来演示,我们来看效果:

image

上次已经说过,08R2-CNSHTSTSVR01这是一台没有安装操作系统的虚拟机,因此移动速度很快,我没有截取到包含进度显示的截图,大家可以自己试一试。同时需要注意一点,如果在移动虚拟机的时候要同时移动存储的话必须指定-IncludeStorage参数。同时默认情况下,虚拟机的配置文件和虚拟磁盘是按照目标主机上的缺省设置来配置。因为我的测试环境中是将VHD和配置文件放在不同目录,所以会关注这一点。

接下来,我们来看看新建虚拟机的命令,New-VM。其实在本系列文章的开始,我已经给出三个参数集中一个参数集的使用例子了。这里在使用Show-Command来看下这三个参数集。

image

毫无疑问,上次给出的例子对应“Existing VHD”这个参数集,“No VHD”和“New VHD”也是非常好理解的。这里我就点到为止了,因为还是希望大家多多探索这些基础命令。

New-VM之后是Remove-VM。看到这里,应该有很多朋友都知道怎么用Remove-VM了,一是指定Name参数,而是通过Get-VM得到VM对象,然后通过管道传递给Remove-VM即可。

接下来是Rename-VM。Rename-VM的参数集构成和Remove-VM类似,运行后的结果也是没有任何悬念。

image

接下来的命令是Repair-VM,从目前的帮助信息中,我暂时找不到一个比较好的例子来说明这个命令的作用,因此暂时先放一放。

接下来的一些列命令,是和虚拟机的启动,停止,重启以及暂停运行有关的。Restart-VM自然是用来重启虚拟机,支持管道和输入虚拟机名。接下来的Resume-VM和Suspend-VM则分别用来恢复和挂起虚拟机,使用方法和之前的类似,就不在多做介绍了。同理,Start-VM和Stop-VM则分别用来启动和停止虚拟机,Stop-VM在默认情况下是告诉虚拟机内的操作性系统执行关闭操作,即所谓的Shutdown。如果需要执行硬关机操作则需要指定-Turnoff参数,当然Stop-VM也可以指定-Save参数来保存虚拟机状态,这和Save-VM的作用类似,目前不清楚这项设计是因为RC还没有从Stop-VM中移除这个参数,还是一种冗余设置。

最后我们再来看看Set-VM命令。不用多少,Set-VM是用来更改VM设置的命令,但是在继续介绍之前,请大家记住Set-VM不能更改VM的所有设置。目前可以更改的设置有当Hyper-V主机启动时虚拟机所采取的行动,启动演示,以及当Hyper-V主机关闭时虚拟机所采取的动作。然后是处理器和内存的设置,下面就来看看演示的截图。

image

至此,花了一定的篇幅来和大家分享了名词部分是VM的所用命令,从下次开始,将为大家介绍名词部分是VHD的命令,敬请期待。

Windows Server 2012 RC 之 Hyper-V 3.0 PowerShell 命令详解 (03)

今天我们继续来过一下和VM有关的命令。根据第一篇文章给出的名词是VM的命令列表,接下来就轮到这些命令中的老大哥Get-VM登场了。

Get-VM用起来很简单,虽然有三个参数集,但实际上常用的参数集应该只有一个,也就是使用虚拟机名来获得虚拟机对象的那个参数集。同时如果需要在多台Hyper-V主机上获得对象,我们还需指定ComputerName参数。具体命令执行效果如下:

image

在刚才这个例子中,我在testserver和cnshhypervsvr02这两台机器上各有一台名为08R2-CNSHTSTSVR01的虚拟机,因此呈现了截图中的效果。那么假设我Name参数中指定了两台Hyper-V主机中各一台虚拟机名称时会发生什么情况呢?我们试试就知道了:

image

嗯,会报错。好了,接下来我再意识流一把,怎么样来确定一台虚拟机是否在一台Hyper-V主机上存在呢,也就是自定义所谓的Test-VM命令,默认模块中是没有这个命令的。我们可以自己编写这个函数,代码如下:

Function Test-VM
{
[cmdletbinding()]
Param
(
[Parameter(Mandatory=$true,Position=1)]
[string[]]$Name,
[Parameter(Mandatory=$true,Position=2)]
[string[]]$ComputerName
)
Process
{
$results = @()
foreach ($cName in $ComputerName) {
foreach ($vName in $Name) {
$result = New-Object System.Management.Automation.PSObject
Try
{
$vm = Get-VM -ComputerName $cName -Name $vName -ErrorAction Stop
if ($vm -ne $null) {
$Existence = $true
} else {
$Existence = $false
}
}
Catch
{
#Display an error message
}
$result | Add-Member -NotePropertyName ComputerName -NotePropertyValue $cName
$result | Add-Member -NotePropertyName Name -NotePropertyValue $vName
$result | Add-Member -NotePropertyName Existence -NotePropertyValue $Existence
$results += $result
}
}
return $results
}

结果也不赖:

image

接下来我们要看的是Measure-VM这个命令。该命令的作用是产生虚拟机的处理器,内存,网络以及存储方面的使用率报表。在使用这个命令之前,必须运行Enable-VMResourceMetering命令启用虚拟机的资源使用记录。这里还需要注意点,默认情况下,Enable-VMResourceMetering需要用户输入虚拟机名,来针对一台或者多台虚拟机启用资源使用记录。大家觉得敲名字烦的话,可以使用Get-VM找到想要设置的虚拟机,然后通过管道传递给Enable-VMResourceMetering即可,命令很简单,Get-VM -Name 08R2-CNSHA* | Enable-VMResourceMetering。完成之后就可以运行Measure-VMResourceMetering来看下报告。

image

结果还是不错的,这里有个参数需要大家注意,MeteringDuration,也就是所谓的使用记录时间。因为资源使用的评估需要一定时间,大家可以根据这个值来判断使用记录是否可以作为资源使用基线。如果需要重置的话,则需要运行Reset-VMResourceMetering,而如果因为种种原因需要禁用资源使用记录的话则可以运行Disable-VMResourceMetering,还是可以通过管道进行批量禁用。

image

本次的介绍就到此结束了,主要过了下Get-VM以及名词部分是VMResourceMetering的命令,接下来还用更多精彩的内容,敬请期待。

(更新完成)