-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathInvoke-ConfigurationManagerCycle.ps1
238 lines (222 loc) · 10.7 KB
/
Invoke-ConfigurationManagerCycle.ps1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#requires -Version 2
# https://www.systemcenterdudes.com/configuration-manager-2012-client-command-list/
# https://blogs.msdn.microsoft.com/timid/2013/03/01/psh-v1-get-tail/
# http://mickitblog.blogspot.co.il/2016/05/initiating-sccm-actions-with.html
function Invoke-ConfigurationManagerCycle
{
<#
.SYNOPSIS
Initiate Configuration Manager Client Scan
.DESCRIPTION
This will initiate an SCCM action
.PARAMETER CycleName
Name of Cycle
#>
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, Position = 0)]
[ValidateSet('Application Deployment Evaluation Cycle','Discovery Data Collection Cycle','File Collection Cycle','Hardware Inventory Cycle','Machine Policy Evaluation Cycle','Machine Policy Retrieval Cycle','Software Inventory Cycle','Software Metering Usage Report Cycle','Software Updates Assignments Evaluation Cycle','Software Update Scan Cycle','Windows Installers Source List Update Cycle')]
[string]$CycleName
)
#Cycles database
$Commands = @{}
$Commands.Add('Application Deployment Evaluation Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000121'
'Log' = "$env:windir\ccm\logs\DCMReporting.log"
'Patterns' = @{
'*FinalRelease*' = 'Completed'
}
})))
$Commands.Add('Discovery Data Collection Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000003'
'Log' = "$env:windir\ccm\logs\InventoryAgent.log"
'Patterns' = @{
'*End of message processing*' = 'Completed'
}
})))
$Commands.Add('File Collection Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000010'
'Log' = "$env:windir\ccm\logs\InventoryAgent.log"
'Patterns' = @{
'*Action completed*' = 'Completed'
'*Exiting as no items to collect*' = 'Completed'
}
})))
$Commands.Add('Hardware Inventory Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000001'
'Log' = "$env:windir\ccm\logs\InventoryAgent.log"
'Patterns' = @{
'*End of message processing*' = 'Completed'
'*already in queue. Message ignored.*' = 'Ignored'
}
})))
$Commands.Add('Machine Policy Evaluation Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000022'
'Log' = "$env:windir\ccm\logs\PolicyEvaluator.log"
'Patterns' = @{
'*instance of CCM_PolicyAgent_PolicyEvaluationComplete*' = 'Completed'
}
})))
$Commands.Add('Machine Policy Retrieval Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000021'
'Log' = "$env:windir\ccm\logs\PolicyAgent.log"
'Patterns' = @{
'*instance of CCM_PolicyAgent_AssignmentsRequested*' = 'Completed'
}
})))
$Commands.Add('Software Inventory Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000002'
'Log' = "$env:windir\ccm\logs\InventoryAgent.log"
'Patterns' = @{
'*Initialization completed in*' = 'Completed'
}
})))
$Commands.Add('Software Metering Usage Report Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000031'
'Log' = "$env:windir\ccm\logs\SWMTRReportGen.log"
'Patterns' = @{
'*No usage data found to generate software metering report*' = 'Completed'
'*Successfully generated report header*' = 'Completed'
'*Message ID of sent message*' = 'Completed'
}
})))
$Commands.Add('Software Updates Assignments Evaluation Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000108'
'Log' = "$env:windir\ccm\logs\ScanAgent.log"
'Patterns' = @{
'*Calling back to client on Scan request complete*' = 'Completed'
}
})))
$Commands.Add('Software Update Scan Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000113'
'Log' = "$env:windir\ccm\logs\ScanAgent.log"
'Patterns' = @{
'*scan completion received*' = 'Completed'
}
})))
$Commands.Add('Windows Installers Source List Update Cycle', (New-Object -TypeName PSObject -Property (@{
'Code' = '00000000-0000-0000-0000-000000000032'
'Log' = "$env:windir\ccm\logs\SrcUpdateMgr.log"
'Patterns' = @{
'*MSI update source list task finished successfully*' = 'Completed'
}
})))
"Running $CycleName"
$Command = [scriptblock]::Create('$null = Invoke-WmiMethod -Namespace root\CCM -Class SMS_Client -Name TriggerSchedule -ArgumentList "{{{0}}}"' -f $Commands[$CycleName].Code)
Wait-StringInFile -Path $Commands[$CycleName].Log -Patterns $Commands[$CycleName].Patterns -Script $Command
}
function Wait-StringInFile
{
<#
.SYNOPSIS
Waits for a string to show in log file
.DESCRIPTION
Similar to 'Get-Content -Path "$env:windir\ccm\logs\PolicyEvaluator.log" -Tail 0 -Wait | % {}' but suppoet Powershell 2.0
.PARAMETER Path
Path to log file
.PARAMETER Patterns
Patterns to find in log file (-like format), hash table of 'Pattern' = 'return code'
.PARAMETER TimeOut
Default is 5 minutes
.PARAMETER Script
Script to run after starting to monitor to the log file
#>
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true, Position = 0)]
[String]$Path,
[Parameter(Mandatory = $true, Position = 1)]
[Hashtable]$Patterns,
[Parameter(Mandatory = $false, Position = 2)]
[TimeSpan]$TimeOut = (New-TimeSpan -Minutes 5),
[Parameter(Mandatory = $false, Position = 3)]
[ScriptBlock]$Script
)
$StartTime = Get-Date
$RotateTime = $StartTime
$Reader = New-Object -TypeName System.IO.StreamReader -ArgumentList (New-Object -TypeName IO.FileStream -ArgumentList ($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, ([IO.FileShare]::Delete,([IO.FileShare]::ReadWrite)) ))
#get end the file
$LastMaxOffset = $Reader.BaseStream.Length
#get encoding
$null = $Reader.Readline()
$Reader.DiscardBufferedData()
#seek to the last max offset
$null = $Reader.BaseStream.Seek($LastMaxOffset, [System.IO.SeekOrigin]::Begin)
if ($Script)
{
& $Script
}
:ReaderLoop while ($true)
{
Start-Sleep -Milliseconds 100
if ((Get-Date) - $StartTime -ge $TimeOut)
{
'TimeOut'
break
}
#detect file rotate
if ($PathR = Get-ChildItem -Path ($Path -replace '\.', '-*.') -ErrorAction SilentlyContinue | Where-Object -FilterScript {
$_.CreationTime -gt $RotateTime
})
{
Write-Verbose -Message "file $PathR rotated in $($PathR.CreationTime) at $LastMaxOffset"
#read the rotated file from LastMaxOffset
$ReaderR = New-Object -TypeName System.IO.StreamReader -ArgumentList (New-Object -TypeName IO.FileStream -ArgumentList ($PathR.FullName, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, ([IO.FileShare]::Delete,([IO.FileShare]::ReadWrite)) )), $Reader.CurrentEncoding
$null = $ReaderR.BaseStream.Seek($LastMaxOffset, [System.IO.SeekOrigin]::Begin)
#read out of the file until the EOF
while (($Line = $ReaderR.ReadLine()) -ne $null)
{
Write-Verbose -Message $Line
foreach ($Pattern in $Patterns.Keys)
{
if ($Line -like $Pattern)
{
$Patterns[$Pattern]
break ReaderLoop
}
}
}
$RotateTime = $PathR.CreationTime
Write-Verbose -Message 'file rotated end'
#go back to the start of the file
$LastMaxOffset = 0
#seek to the Beginning
$null = $Reader.BaseStream.Seek($LastMaxOffset, [System.IO.SeekOrigin]::Begin)
}
#if the file size has not changed, idle
if ($Reader.BaseStream.Length -eq $LastMaxOffset)
{
continue
}
#read out of the file until the EOF
while (($Line = $Reader.ReadLine()) -ne $null)
{
Write-Verbose -Message $Line
foreach ($Pattern in $Patterns.Keys)
{
if ($Line -like $Pattern)
{
$Patterns[$Pattern]
break ReaderLoop
}
}
}
#update the last max offset
$LastMaxOffset = $Reader.BaseStream.Position
}
}
<#
Invoke-ConfigurationManagerCycle -CycleName 'Machine Policy Retrieval Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Machine Policy Evaluation Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Software Update Scan Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Software Updates Assignments Evaluation Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Application Deployment Evaluation Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Discovery Data Collection Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'File Collection Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Hardware Inventory Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Software Inventory Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Software Metering Usage Report Cycle'
Invoke-ConfigurationManagerCycle -CycleName 'Windows Installers Source List Update Cycle'
#>