├── 27 WSUS Servers
├── Get-WSUSPortNumbers.ps1
├── Set-LedbatWSUS.ps1
├── Set-WSUSContentDir.ps1
├── Set-WSUSContentDirAnonAuth.ps1
├── Set-WSUSSSLCertificate.ps1
├── Test-IsWSUSServer.ps1
├── Test-WSUSIsSSL.ps1
├── Test-WSUSPostInstallRan.ps1
└── readme.md
├── Add-FunctionToProfile.ps1
├── Battery_Health.sql
├── CollectionSummary.sql
├── ConfigMgrSUP_LastScan_Summary.sql
├── Configure-DedupeForMe - SCCM
├── CB - SCCM Distribution Point.cab
├── Set-CMDPDedupConfiguration.ps1
└── readme.md
├── Content_NotOnAllDPGroup.sql
├── Convert-CoManagementWorkload.ps1
├── Create-SecurityProviders-CI_CB.ps1
├── DB-Size-Queries.sql
├── Get-30DayHinv_Summary.sql
├── Get-BuzzPhrase.ps1
├── Get-CCMBaseline.ps1
├── Get-CCMLogFile.ps1
├── Get-CMClientMaintenanceWindow.ps1
├── Get-CMCollectionSummary.ps1
├── Get-CMHTTPSReadiness.ps1
├── Get-CMSoftwareUpdatePointSummary.ps1
├── Get-HinvFrequency.sql
├── Get-LenovoBIOSSettings.ps1
├── Get-PendingSCCMPatches.ps1
├── Get-SupersededUpdatesInSUGBySUG.ps1
├── Get-WQLObject.ps1
├── Get-WmiRegistryProperty.ps1
├── Invoke-CCMBaseline.ps1
├── Invoke-CCMClientAction.ps1
├── Invoke-SCCMUpdates.ps1
├── Invoke-SQLAGPatchPrep.ps1
├── Invoke-UpdateScanAfterSSU
├── CI - Invoke-UpdateScanAfterSSU - Scheduled Task.cab
├── Invoke-UpdateScanAfterSSU.ps1
└── readme.md
├── MEMCM_PolicyPriority
├── README.md
├── Set-CMAntimalwarePolicyPriority.ps1
└── Set-CMClientSettingPriority.ps1
├── MachineCertInv.ps1
├── New-CMGlobalConditionRule.ps1
├── New-CMScheduleStartTime.ps1
├── New-ClientActionScheduledTask.ps1
├── New-LoopAction.ps1
├── New-PostTeamsMachineWideInstallScheduledTask.ps1
├── Office365
├── New-365DynamicApp.ps1
├── O365-PrjOnline-VisPro-2016.xml
├── O365-PrjOnline-VisPro-2019.xml
├── O365-PrjOnline-VisStd-2016.xml
├── O365-PrjOnline-VisStd-2019.xml
├── O365-PrjOnline.xml
├── O365-PrjPro-2016.xml
├── O365-PrjPro-2019.xml
├── O365-PrjStd-2016.xml
├── O365-PrjStd-2019.xml
├── O365-VisOnline-PrjOnline.xml
├── O365-VisOnline-PrjPro-2016.xml
├── O365-VisOnline-PrjPro-2019.xml
├── O365-VisOnline-PrjStd-2016.xml
├── O365-VisOnline-PrjStd-2019.xml
├── O365-VisOnline.xml
├── O365-VisPro-2016-PrjOnline.xml
├── O365-VisPro-2016.xml
├── O365-VisPro-2019-PrjOnline.xml
├── O365-VisPro-2019.xml
├── O365-VisPro-PrjPro-2016.xml
├── O365-VisPro-PrjPro-2019.xml
├── O365-VisPro-PrjStd-2016.xml
├── O365-VisPro-PrjStd-2019.xml
├── O365-VisStd-2016-PrjOnline.xml
├── O365-VisStd-2016.xml
├── O365-VisStd-2019-PrjOnline.xml
├── O365-VisStd-2019.xml
├── O365-VisStd-PrjPro-2016.xml
├── O365-VisStd-PrjPro-2019.xml
├── O365-VisStd-PrjStd-2016.xml
├── O365-VisStd-PrjStd-2019.xml
├── O365.xml
├── PrjOnline.xml
├── PrjPro-2016.xml
├── PrjPro-2019.xml
├── PrjStd-2016.xml
├── PrjStd-2019.xml
├── VisOnline.xml
├── VisPro-2016.xml
├── VisPro-2019.xml
├── VisStd-2016.xml
├── VisStd-2019.xml
└── readme.md
├── README.md
├── RemoveExpiredUpdates.sql
├── Repair-CMClientSettings
├── Reprovision Windows 10 Apps
├── Get-DeprovisionedAppX.ps1
├── Inventory-DeprovisionedAppX.ps1
└── Reprovision-AppX.ps1
├── Script-InvokeBaseline.ps1
├── Set-CMDistributionPointMaintenanceMode.ps1
├── Set-DefaultSecureProtocols.ps1
├── Set-WSUSContentPath.ps1
├── Set-WSUSContentPoolAuth.ps1
├── Start-CMClientAction.ps1
├── Start-IISLogCleanup.ps1
└── prompt.ps1
/27 WSUS Servers/Get-WSUSPortNumbers.ps1:
--------------------------------------------------------------------------------
1 | function Get-WSUSPortNumbers {
2 | [CmdletBinding()]
3 | <#
4 | .SYNOPSIS
5 | Return the port numbers in use by WSUS
6 | .DESCRIPTION
7 | This function will automatically determine the ports in use by WSUS, and return them as a PSCustomObject.
8 |
9 | If WSUS is set to use any custom port other than 80/443 it
10 | automatically determines the HTTP as noted in the link below
11 | https://docs.microsoft.com/en-us/windows-server/administration/windows-server-update-services/deploy/2-configure-wsus#configure-ssl-on-the-wsus-server
12 | ... if you use any port other than 443 for HTTPS traffic,
13 | WSUS will send clear HTTP traffic over the port that numerically
14 | comes before the port for HTTPS. For example, if you use port 8531 for HTTPS,
15 | WSUS will use port 8530 for HTTP.
16 | .EXAMPLE
17 | PS C:\> Get-WSUSPortNumbers -WSUSServer (Get-WSUSServer)
18 | .INPUTS
19 | [Microsoft.UpdateServices.Internal.BaseApi.UpdateServer]
20 | .OUTPUTS
21 | [PSCustomerObject]
22 | .NOTES
23 | FileName: Get-WSUSPortNumbers.ps1
24 | Author: Cody Mathis
25 | Contact: @CodyMathis123
26 | Created: 6/29/2020
27 | Updated: 6/29/2020
28 | #>
29 | param (
30 | [Parameter(Mandatory = $true)]
31 | [object]$WSUSServer
32 | )
33 | #region Determine WSUS Port Numbers
34 | $WSUS_Port1 = $WSUSServer.PortNumber
35 | $WSUS_IsSSL = $WSUSServer.UseSecureConnection
36 |
37 | switch ($WSUS_IsSSL) {
38 | $true {
39 | switch ($WSUS_Port1) {
40 | 443 {
41 | $WSUS_Port2 = 80
42 | }
43 | default {
44 | $WSUS_Port2 = $WSUS_Port1 - 1
45 | }
46 | }
47 | }
48 | $false {
49 | $Wsus_Port2 = $null
50 | }
51 | }
52 | #endregion Determine WSUS Port Numbers
53 |
54 | return [PSCustomObject]@{
55 | WSUSIsSSL = $WSUS_IsSSL
56 | WSUSPort1 = $WSUS_Port1
57 | WSUSPort2 = $WSUS_Port2
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/27 WSUS Servers/Set-LedbatWSUS.ps1:
--------------------------------------------------------------------------------
1 | #region detection/remediation
2 | #region define variables
3 | $Remediate = $false
4 | #endregion define variables
5 |
6 | try {
7 | $WSUS_Server = Get-WsusServer -ErrorAction Stop
8 | }
9 | catch {
10 | # This is not a WSUS server, or it is in an error state. Return compliant.
11 | return $true
12 | }
13 |
14 | #region helper functions
15 | function Get-WSUSPortNumbers {
16 | [CmdletBinding()]
17 | <#
18 | .SYNOPSIS
19 | Return the port numbers in use by WSUS
20 | .DESCRIPTION
21 | This function will automatically determine the ports in use by WSUS, and return them as a PSCustomObject.
22 |
23 | If WSUS is set to use any custom port other than 80/443 it
24 | automatically determines the HTTP as noted in the link below
25 | https://docs.microsoft.com/en-us/windows-server/administration/windows-server-update-services/deploy/2-configure-wsus#configure-ssl-on-the-wsus-server
26 | ... if you use any port other than 443 for HTTPS traffic,
27 | WSUS will send clear HTTP traffic over the port that numerically
28 | comes before the port for HTTPS. For example, if you use port 8531 for HTTPS,
29 | WSUS will use port 8530 for HTTP.
30 | .EXAMPLE
31 | PS C:\> Get-WSUSPortNumbers -WSUSServer (Get-WSUSServer)
32 | .INPUTS
33 | [Microsoft.UpdateServices.Internal.BaseApi.UpdateServer]
34 | .OUTPUTS
35 | [PSCustomerObject]
36 | .NOTES
37 | FileName: Get-WSUSPortNumbers.ps1
38 | Author: Cody Mathis
39 | Contact: @CodyMathis123
40 | Created: 6/29/2020
41 | Updated: 6/29/2020
42 | #>
43 | param (
44 | [Parameter(Mandatory = $true)]
45 | [object]$WSUSServer
46 | )
47 | #region Determine WSUS Port Numbers
48 | $WSUS_Port1 = $WSUSServer.PortNumber
49 | $WSUS_IsSSL = $WSUSServer.UseSecureConnection
50 |
51 | switch ($WSUS_IsSSL) {
52 | $true {
53 | switch ($WSUS_Port1) {
54 | 443 {
55 | $WSUS_Port2 = 80
56 | }
57 | default {
58 | $WSUS_Port2 = $WSUS_Port1 - 1
59 | }
60 | }
61 | }
62 | $false {
63 | $Wsus_Port2 = $null
64 | }
65 | }
66 | #endregion Determine WSUS Port Numbers
67 |
68 | return [PSCustomObject]@{
69 | WSUSIsSSL = $WSUS_IsSSL
70 | WSUSPort1 = $WSUS_Port1
71 | WSUSPort2 = $WSUS_Port2
72 | }
73 | }
74 | #endregion
75 |
76 | switch ($WSUS_Server -is [Microsoft.UpdateServices.Internal.BaseApi.UpdateServer]) {
77 | $true {
78 | $WSUSPorts = Get-WSUSPortNumbers -WSUSServer $WSUS_Server
79 |
80 | $WSUS_Port1 = $WSUSPorts.WSUSPort1
81 | $WSUS_Port2 = $WSUSPorts.WSUSPort2
82 |
83 | $LEDBAT_Enabled = [bool](Get-NetTCPSetting -SettingName InternetCustom -CongestionProvider LEDBAT -ErrorAction SilentlyContinue)
84 | $CustomPort1Set = [bool](Get-NetTransportFilter -LocalPortStart $WSUS_Port1 -LocalPortEnd $WSUS_Port1 -SettingName InternetCustom -RemotePortStart 0 -RemotePortEnd 65535 -ErrorAction SilentlyContinue)
85 | if ($null -ne $Wsus_Port2) {
86 | $CustomPort2Set = [bool](Get-NetTransportFilter -LocalPortStart $WSUS_Port2 -LocalPortEnd $WSUS_Port2 -SettingName InternetCustom -RemotePortStart 0 -RemotePortEnd 65535 -ErrorAction SilentlyContinue)
87 | }
88 | else {
89 | $CustomPort2Set = $true
90 | }
91 | switch ($LEDBAT_Enabled -and $CustomPort1Set -and $CustomPort2Set) {
92 | $true {
93 | return $true
94 | }
95 | $false {
96 | switch ($LEDBAT_Enabled) {
97 | $false {
98 | switch ($Remediate) {
99 | $true {
100 | try {
101 | Set-NetTCPSetting -SettingName InternetCustom -CongestionProvider LEDBAT -ErrorAction Stop
102 | }
103 | catch {
104 | return $false
105 | }
106 | }
107 | }
108 | }
109 | }
110 | switch ($CustomPort1Set) {
111 | $false {
112 | switch ($Remediate) {
113 | $true {
114 | try {
115 | New-NetTransportFilter -SettingName InternetCustom -LocalPortStart $WSUS_Port1 -LocalPortEnd $WSUS_Port1 -RemotePortStart 0 -RemotePortEnd 65535 -ErrorAction Stop
116 | }
117 | catch {
118 | return $false
119 | }
120 | }
121 | }
122 | }
123 | }
124 | switch ($CustomPort2Set) {
125 | $false {
126 | switch ($Remediate) {
127 | $true {
128 | try {
129 | New-NetTransportFilter -SettingName InternetCustom -LocalPortStart $WSUS_Port2 -LocalPortEnd $WSUS_Port2 -RemotePortStart 0 -RemotePortEnd 65535 -ErrorAction Stop
130 | }
131 | catch {
132 | return $false
133 | }
134 | }
135 | }
136 | }
137 | }
138 | return $Remediate
139 | }
140 | }
141 | }
142 | $false {
143 | return $true
144 | }
145 | }
146 | #endregion detection/remediation
147 |
--------------------------------------------------------------------------------
/27 WSUS Servers/Set-WSUSContentDir.ps1:
--------------------------------------------------------------------------------
1 | $Remediate = $false
2 |
3 | $PathShouldBeROOT = Get-ItemProperty -Path "registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Update Services\Server\Setup" -Name ContentDir | Select-Object -ExpandProperty ContentDir
4 | $PathShouldBe = Join-Path -Path $PathShouldBeROOT -ChildPath 'WSUSContent'
5 |
6 | [Void][Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
7 | $serverManager = New-Object Microsoft.Web.Administration.ServerManager
8 | $site = $serverManager.Sites | Where-Object { $_.Name -eq "WSUS Administration" }
9 | $rootApp = $site.Applications | Where-Object { $_.Path -eq "/" }
10 | $rootVdir = $rootApp.VirtualDirectories | Where-Object { $_.Path -eq "/Content" }
11 | $CurrentPath = $rootVdir.PhysicalPath
12 |
13 | switch ($CurrentPath -eq $PathShouldBe) {
14 | $true {
15 | $true
16 | }
17 | $false {
18 | switch ($Remediate) {
19 | $true {
20 | $rootVdir.PhysicalPath = $PathShouldBe
21 | $null = $serverManager.CommitChanges()
22 | $true
23 | }
24 | $false {
25 | $false
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/27 WSUS Servers/Set-WSUSContentDirAnonAuth.ps1:
--------------------------------------------------------------------------------
1 | $Remediate = $false
2 |
3 | Import-Module WebAdministration
4 | $UseAppPoolIdentity = (Get-WebConfiguration "/system.applicationHost/sites/site[@name='WSUS Administration']/application[@path='/']/virtualdirectory[@path='/Content']").userName -eq [string]::Empty
5 | switch ($UseAppPoolIdentity) {
6 | $true {
7 | $true
8 | }
9 | $false {
10 | switch ($Remediate) {
11 | $true {
12 | Set-WebConfiguration "/system.applicationHost/sites/site[@name='WSUS Administration']/application[@path='/']/virtualdirectory[@path='/Content']" -Value @{userName = ''; password = '' }
13 | $true
14 | }
15 | $false {
16 | $false
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/27 WSUS Servers/Set-WSUSSSLCertificate.ps1:
--------------------------------------------------------------------------------
1 | $Remediate = $false
2 | $IssuingCA = 'Auto Enrollment Issuing CA'
3 | $Website = 'WSUS Administration'
4 |
5 | try {
6 | $WSUS_Server = Get-WsusServer -ErrorAction Stop
7 | }
8 | catch {
9 | # This is not a WSUS server, or it is in an error state. Return compliant.
10 | return $true
11 | }
12 | #region helper functions
13 | function Get-WSUSPortNumbers {
14 | [CmdletBinding()]
15 | <#
16 | .SYNOPSIS
17 | Return the port numbers in use by WSUS
18 | .DESCRIPTION
19 | This function will automatically determine the ports in use by WSUS, and return them as a PSCustomObject.
20 |
21 | If WSUS is set to use any custom port other than 80/443 it
22 | automatically determines the HTTP as noted in the link below
23 | https://docs.microsoft.com/en-us/windows-server/administration/windows-server-update-services/deploy/2-configure-wsus#configure-ssl-on-the-wsus-server
24 | ... if you use any port other than 443 for HTTPS traffic,
25 | WSUS will send clear HTTP traffic over the port that numerically
26 | comes before the port for HTTPS. For example, if you use port 8531 for HTTPS,
27 | WSUS will use port 8530 for HTTP.
28 | .EXAMPLE
29 | PS C:\> Get-WSUSPortNumbers -WSUSServer (Get-WSUSServer)
30 | .INPUTS
31 | [Microsoft.UpdateServices.Internal.BaseApi.UpdateServer]
32 | .OUTPUTS
33 | [PSCustomerObject]
34 | .NOTES
35 | FileName: Get-WSUSPortNumbers.ps1
36 | Author: Cody Mathis
37 | Contact: @CodyMathis123
38 | Created: 6/29/2020
39 | Updated: 6/29/2020
40 | #>
41 | param (
42 | [Parameter(Mandatory = $true)]
43 | [object]$WSUSServer
44 | )
45 | #region Determine WSUS Port Numbers
46 | $WSUS_Port1 = $WSUSServer.PortNumber
47 | $WSUS_IsSSL = $WSUSServer.UseSecureConnection
48 |
49 | switch ($WSUS_IsSSL) {
50 | $true {
51 | switch ($WSUS_Port1) {
52 | 443 {
53 | $WSUS_Port2 = 80
54 | }
55 | default {
56 | $WSUS_Port2 = $WSUS_Port1 - 1
57 | }
58 | }
59 | }
60 | $false {
61 | $Wsus_Port2 = $null
62 | }
63 | }
64 | #endregion Determine WSUS Port Numbers
65 |
66 | return [PSCustomObject]@{
67 | WSUSIsSSL = $WSUS_IsSSL
68 | WSUSPort1 = $WSUS_Port1
69 | WSUSPort2 = $WSUS_Port2
70 | }
71 | }
72 | #endregion
73 |
74 | $WSUSPorts = Get-WSUSPortNumbers -WSUSServer $WSUS_Server
75 | if ($WSUSPorts.WSUSIsSSL) {
76 | $PortNumber = $WSUSPorts.WSUSPort1
77 | }
78 | else {
79 | # WSUS is not configured to use SSL. Return compliant.
80 | return 'Compliant'
81 | }
82 |
83 | $AllCerts = Get-ChildItem -Path Cert:\LocalMachine\My\
84 | $ServerAuth = $allCerts | Where-Object { $_.issuer -match $IssuingCA -and $_.Subject -match $env:COMPUTERNAME -and $_.EnhancedKeyUsageList.FriendlyName -contains 'Server Authentication' } | Sort-Object -Property NotAfter | Select-Object -ExpandProperty Thumbprint -Last 1
85 | $Binding = Get-WebBinding -Name $Website -Protocol https
86 |
87 | if ($null -eq $ServerAuth) {
88 | return 'No Cert Found'
89 | }
90 |
91 | switch ($null -ne $Binding) {
92 | $true {
93 | continue
94 | }
95 | $false {
96 | switch ($Remediate) {
97 | $true {
98 | $null = New-WebBinding -Name $Website -Protocol https -Port $PortNumber
99 | $Binding = Get-WebBinding -Name $Website -Protocol https
100 | }
101 | $false {
102 | return 'HTTPS Binding does not exist'
103 | }
104 | }
105 |
106 | }
107 | }
108 |
109 | switch ($Binding.certificateHash -eq $ServerAuth) {
110 | $true {
111 | return 'Compliant'
112 | }
113 | $false {
114 | switch ($Remediate) {
115 | $true {
116 | $Binding.AddSslCertificate($ServerAuth, 'MY')
117 | return 'Compliant'
118 | }
119 | $false {
120 | return 'Incorrect Cert Bound'
121 | }
122 | }
123 | }
124 | }
--------------------------------------------------------------------------------
/27 WSUS Servers/Test-IsWSUSServer.ps1:
--------------------------------------------------------------------------------
1 | try {
2 | [Void][Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
3 | $serverManager = New-Object Microsoft.Web.Administration.ServerManager -ErrorAction SilentlyContinue
4 | }
5 | catch {
6 | # Deliberate empty return. If anything above throws an error, we assume we are not on a box with IIS
7 | exit 0
8 | }
9 |
10 | if ((Get-CimInstance -Query "SELECT Name FROM Win32_ServerFeature WHERE Name ='Windows Server Update Services'").Name -and $serverManager.ApplicationPools.Name -contains 'WsusPool') {
11 | Write-Host 'WSUS Is Installed'
12 | }
--------------------------------------------------------------------------------
/27 WSUS Servers/Test-WSUSIsSSL.ps1:
--------------------------------------------------------------------------------
1 | try {
2 | [Void][Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
3 | $serverManager = New-Object Microsoft.Web.Administration.ServerManager -ErrorAction SilentlyContinue
4 | }
5 | catch {
6 | # Deliberate empty return. If anything above throws an error, we assume we are not on a box with IIS
7 | exit 0
8 | }
9 |
10 | $WSUS_ConfigKey = 'registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Update Services\Server\Setup'
11 |
12 | try {
13 | $ServerCertName = Get-ItemPropertyValue -Path $WSUS_ConfigKey -Name 'ServerCertificateName' -ErrorAction Stop
14 | $UsingSSL = Get-ItemPropertyValue -Path $WSUS_ConfigKey -Name 'UsingSSL' -ErrorAction Stop
15 | if ($serverManager.ApplicationPools.Name -contains 'WsusPool' -and $env:COMPUTERNAME -match $ServerCertName -and $UsingSSL) {
16 | Write-Host 'WSUS Server is SSL'
17 | }
18 | }
19 | catch {
20 | # Deliberate empty return. If anything above throws an error, we assume we are not on an SSL WSUS box
21 | exit 0
22 | }
--------------------------------------------------------------------------------
/27 WSUS Servers/Test-WSUSPostInstallRan.ps1:
--------------------------------------------------------------------------------
1 | try {
2 | [Void][Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
3 | $serverManager = New-Object Microsoft.Web.Administration.ServerManager
4 | }
5 | catch {
6 | # Deliberate empty return. If anything above throws an error, we assume we are not on a box with IIS
7 | exit 0
8 | }
9 |
10 | try {
11 | $UpdateServices = (Get-ItemProperty -Path "registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Update Services\Server\Setup\Installed Role Services" -Name 'UpdateServices-Services' -ErrorAction SilentlyContinue).'UpdateServices-Services'
12 | if ($UpdateServices -eq 2 -and (Get-CimInstance -Query "SELECT Name FROM Win32_ServerFeature WHERE Name ='Windows Server Update Services'").Name -and $serverManager.ApplicationPools.Name -contains 'WsusPool') {
13 | Write-Host 'WSUS PostInstall Has Ran'
14 | }
15 | }
16 | catch {
17 | # Deliberate empty return. If anything above throws an error, we assume we are not on a WSUS box
18 | exit 0
19 | }
--------------------------------------------------------------------------------
/27 WSUS Servers/readme.md:
--------------------------------------------------------------------------------
1 | https://sccmf12twice.com/?p=12621&preview=true
2 |
--------------------------------------------------------------------------------
/Add-FunctionToProfile.ps1:
--------------------------------------------------------------------------------
1 | function Add-FunctionToProfile {
2 | <#
3 | .SYNOPSIS
4 | Add a function to your profile
5 | .DESCRIPTION
6 | This function is used to append a function to your PowerShell profile. You provide a function name, and if it has a script block
7 | then it will be appended to your PowerShell profile with the function name provided.
8 | .PARAMETER FunctionToAdd
9 | The name of the function(s) you wish to add to your profile. You can provide multiple.
10 | .EXAMPLE
11 | PS C:\> Add-FunctionToProfile -FunctionToAdd 'Get-CMClientMaintenanceWindow'
12 | .NOTES
13 | If a function doesn't have a script block, then it cannot be added to your profile
14 | #>
15 | param(
16 | [Parameter(Mandatory = $True)]
17 | [string[]]$FunctionToAdd
18 | )
19 | foreach ($FunctionName in $FunctionToAdd) {
20 | try {
21 | $Function = Get-Command -Name $FunctionName -CommandType Function -ErrorAction Stop
22 | }
23 | catch {
24 | Write-Error "Failed to find the specified function [Name = '$FunctionName']"
25 | continue
26 | }
27 | $ScriptBlock = $Function.ScriptBlock
28 | if ($null -ne $ScriptBlock) {
29 | $FuncToAdd = [string]::Format("`r`nfunction {0} {{{1}}}", $FunctionName, $ScriptBlock)
30 | ($FuncToAdd -split "`n") | Add-Content -Path $PROFILE
31 | }
32 | else {
33 | Write-Error "Function $FunctionName does not have a Script Block and cannot be added to your profile."
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Battery_Health.sql:
--------------------------------------------------------------------------------
1 | SELECT DISTINCT s.Netbios_Name0
2 | , os.InstallDate0
3 | , csp.Version0
4 | , csp.Name0
5 | , cycle.CycleCount0
6 | , batcapac.FullChargedCapacity0
7 | , batstat.DesignedCapacity0
8 | , CASE
9 | WHEN batcapac.FullChargedCapacity0 <= batstat.DesignedCapacity0 THEN CAST((100 * batcapac.FullChargedCapacity0 / batstat.DesignedCapacity0) AS FLOAT)
10 | ELSE 100
11 | END AS [BatteryHealth]
12 | , cycle.InstanceName0
13 | , bat.Name0 AS [BatteryName]
14 | , bat.DesignVoltage0
15 | , bat.Status0
16 | , portbat.Location0
17 | , portbat.Manufacturer0
18 | FROM v_R_System_Valid s
19 | JOIN v_GS_OPERATING_SYSTEM os ON os.ResourceID = s.ResourceID
20 | JOIN v_GS_COMPUTER_SYSTEM_PRODUCT csp ON csp.ResourceID = s.ResourceID
21 | JOIN v_GS_BATTERYCYCLECOUNT cycle ON cycle.ResourceID = s.ResourceID
22 | JOIN v_GS_BATTERYSTATICDATA batstat ON batstat.ResourceID = s.ResourceID AND batstat.InstanceName0 = cycle.InstanceName0
23 | JOIN v_GS_BATTERYFULLCHARGEDCAPACI batcapac ON batcapac.ResourceID = s.ResourceID AND batcapac.InstanceName0 = cycle.InstanceName0
24 | LEFT JOIN v_GS_BATTERY bat ON bat.ResourceID = s.ResourceID AND bat.Name0 = batstat.DeviceName0
25 | LEFT JOIN v_GS_PORTABLE_BATTERY portbat ON portbat.ResourceID = s.ResourceID AND portbat.Name0 = batstat.DeviceName0
26 | ORDER BY 1
27 |
--------------------------------------------------------------------------------
/ConfigMgrSUP_LastScan_Summary.sql:
--------------------------------------------------------------------------------
1 | SELECT s.Netbios_Name0 AS 'Name'
2 | , s.ResourceID
3 | , srn.Resource_Names0 AS 'FQDN'
4 | , s.Resource_Domain_OR_Workgr0 AS 'DOMAIN'
5 | , os.Caption0 AS 'Operating System'
6 | , sn.StateDescription AS 'LastScanState'
7 | , scan.LastScanTime
8 | , scan.LastErrorCode
9 | , scan.LastScanPackageLocation
10 | , wsStatus.LastHWScan AS 'Last Hardware Scan'
11 | FROM v_R_System s
12 | JOIN v_RA_System_ResourceNames srn ON s.ResourceID = srn.ResourceID
13 | JOIN v_UpdateScanStatus scan ON s.ResourceID = scan.ResourceID
14 | JOIN v_GS_WORKSTATION_STATUS wsStatus ON s.ResourceID = wsStatus.ResourceID
15 | JOIN v_GS_OPERATING_SYSTEM os ON s.ResourceID = os.ResourceID
16 | JOIN v_StateNames sn ON sn.StateID = scan.LastScanState AND sn.TopicType = 501
--------------------------------------------------------------------------------
/Configure-DedupeForMe - SCCM/CB - SCCM Distribution Point.cab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodyMathis123/CM-Ramblings/ed952ee8966a9914ba5bff976020b5f16c20758f/Configure-DedupeForMe - SCCM/CB - SCCM Distribution Point.cab
--------------------------------------------------------------------------------
/Configure-DedupeForMe - SCCM/readme.md:
--------------------------------------------------------------------------------
1 | https://sccmf12twice.com/2019/07/configure-dedupeforme-sccm/
2 |
--------------------------------------------------------------------------------
/Content_NotOnAllDPGroup.sql:
--------------------------------------------------------------------------------
1 | DECLARE @allDPgroupID uniqueidentifier = (SELECT TOP 1 GroupID FROM v_SMS_DistributionPointGroup ORDER BY membercount DESC)
2 | DECLARE @allDPgroupMemberCount int = (SELECT TOP 1 MemberCount FROM v_SMS_DistributionPointGroup ORDER BY membercount DESC)
3 |
4 | SELECT DISTINCT dpgp.PkgID
5 | , p.packagetype
6 | , bycount.TargeteddDPCount
7 | FROM v_DPGroupPackages dpgp
8 | JOIN v_package p ON p.packageid = dpgp.PkgID
9 | JOIN (
10 | SELECT cdss.pkgid
11 | , cdss.TargeteddDPCount
12 | FROM v_ContDistStatSummary cdss
13 | WHERE TargeteddDPCount not in (@allDPgroupMemberCount,0)
14 | ) bycount ON bycount.PkgID = dpgp.PkgID
15 | WHERE p.packageid not in (
16 | SELECT DISTINCT PkgID
17 | FROM v_DPGroupPackages
18 | WHERE groupid = @allDPgroupID
19 | )
20 |
--------------------------------------------------------------------------------
/Convert-CoManagementWorkload.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | Convert CoMgmt workloads from int to text and vice-versa
4 | .DESCRIPTION
5 | In log files, WMI and the database we are presented with an integer values for the currently enabled functions with Co-Management.
6 | This function has two ParameterSets.
7 | For the 'TranslateWorkload' ParameterSet you can input an integer (0-255) and return a string array of the workloads that are enabled.
8 | For the 'GenerateWorkload' ParameterSet you can input a string array of the workloads you'd like and it will return the translated integer equivalent.
9 | .PARAMETER DesiredWorkload
10 | Specify the workloads you'd like to generate a translated integer for. The options are are below. It will be translated using a bitwise and operator.
11 | 'Client Apps',
12 | 'Compliance policies',
13 | 'Device Configuration',
14 | 'Endpoint Protection',
15 | 'Office Click-To-Run apps',
16 | 'Resource access policies',
17 | 'Windows Updates policies'
18 | .PARAMETER Workload
19 | Translate an integer workload to the named workload values using bitwise or operator.
20 | .EXAMPLE
21 | PS C:\> .\Convert-CoManagementWorkload -DesiredWorkload 'Windows Updates Policies','Office Click-To-Run apps'
22 | 145
23 |
24 | This would return a value of 145, which could be used to update a configuration item.
25 | .EXAMPLE
26 | PS C:\> .\Convert-CoManagementWorkload -Workload 145
27 | Office Click-to-Run apps
28 | Windows Updates Policies
29 |
30 | This translates the workload integer value of 145 to the component that would be enabled, Office C2R and WUFB.
31 | .NOTES
32 | FileName: Convert-CoManagementWorkload.ps1
33 | Author: Cody Mathis
34 | Contact: @CodyMathis123
35 | Created: 1/28/2019
36 | Updated: 6/17/2020
37 |
38 | Version History:
39 | 1.0.0 - (1/28/2019) Initial script creation
40 | 1.0.1 - (1/29/2019) Added proper help and commenting and specified OutputType
41 | 1.0.2 - (8/21/2019) Update workloads for 1906
42 | 1.0.3 - (6/17/2020) Stop using arraylist
43 | #>
44 | [OutputType([int], ParameterSetName = 'GenerateWorkload')]
45 | [OutputType([string[]], ParameterSetName = 'TranslateWorkload')]
46 | param(
47 | [Parameter(Mandatory = $True, ParameterSetName = 'GenerateWorkload')]
48 | [ValidateSet('Client Apps',
49 | 'Compliance policies',
50 | 'Device Configuration',
51 | 'Endpoint Protection',
52 | 'Office Click-To-Run apps',
53 | 'Resource access policies',
54 | 'Windows Updates policies'
55 | )]
56 | [string[]]
57 | $DesiredWorkload,
58 | [Parameter(Mandatory = $True, ParameterSetName = 'TranslateWorkload')]
59 | [ValidateRange(0, 255)]
60 | [int]
61 | $Workload
62 | )
63 |
64 | switch ($PSCmdlet.ParameterSetName) {
65 | 'GenerateWorkload' {
66 | $Workloads = @{
67 | "Compliance Policies" = 3;
68 | "Resource access policies" = 5;
69 | "Device Configuration" = 9;
70 | "Windows Updates Policies" = 17;
71 | "Endpoint Protection" = 33;
72 | "Client Apps" = 65;
73 | "Office Click-to-Run apps" = 129;
74 | }
75 | # Creating an arraylist and adding all the integer values for our workloads to the arraylist.
76 | $ToCalc = foreach ($Option in $DesiredWorkload) {
77 | $Workloads[$Option]
78 | }
79 |
80 | <#
81 | In order to calculate our output value we join all of our converted workload integers with -bor giving us something like '17 -bor 129'
82 | This is then converted to a scriptblock so we can execute it to receive an integer output. This is a bitwise operation.
83 | #>
84 | $Calculation = $ToCalc -join ' -bor '
85 | $Output = [scriptblock]::Create($Calculation)
86 | & $Output
87 | }
88 | 'TranslateWorkload' {
89 | $Workloads = @{
90 | 3 = "Compliance policies";
91 | 5 = "Resource access policies"
92 | 9 = "Device Configuration"
93 | 17 = "Windows Updates Policies";
94 | 33 = "Endpoint Protection"
95 | 65 = "Client Apps";
96 | 129 = "Office Click-to-Run apps"
97 | }
98 |
99 | # If our workload input is greater than 1, we perform a -band comparison against all possible workloads and return the matches
100 | if ($Workload -gt 1) {
101 | foreach ($Value in $Workloads.Keys) {
102 | if (($Value -band $Workload) -eq $Value) {
103 | $Workloads[$value]
104 | }
105 | }
106 | }
107 | else {
108 | Write-Output 'None'
109 | }
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Create-SecurityProviders-CI_CB.ps1:
--------------------------------------------------------------------------------
1 | # define all the protocols available
2 | $ProtocolList = @('SSL 2.0', 'SSL 3.0', 'TLS 1.0', 'TLS 1.1', 'TLS 1.2')
3 | # specify all the protocols that should remain enabled
4 | $EnableList = @('TLS 1.2')
5 |
6 | $SetKeyParams = @{
7 | DataType = 'Integer'
8 | Hive = 'LocalMachine'
9 | ReportNoncompliance = $true
10 | ExpressionOperator = 'IsEquals'
11 | Remediate = $true
12 | ValueRule = $true
13 | NoncomplianceSeverity = 'Warning'
14 | RemediateDword = $true
15 | Is64Bit = $true
16 | }
17 |
18 | $GetKeyExistanceParams = @{
19 | Existence = 'MustExist'
20 | Hive = 'LocalMachine'
21 | DataType = 'Integer'
22 | ExistentialRule = $true
23 | NoncomplianceSeverity = 'Warning'
24 | RemediateDword = $true
25 | Is64Bit = $true
26 | }
27 |
28 | $EnabledListString = $EnableList -join ', '
29 | $BL = New-CMBaseline -Name "Enforce $EnabledListString" -Description "Configures the machine to only use $EnabledListString"
30 | foreach ($Protocol in $ProtocolList) {
31 | if ($Protocol -in $EnableList) {
32 | $Name = "Registry - Enable $Protocol"
33 | $Description = "Forces $Protocol to be enabled"
34 | }
35 | else {
36 | $Name = "Registry - Disable $Protocol"
37 | $Description = "Forces $Protocol to be disabled"
38 | }
39 | $CI = New-CMConfigurationItem -Name $Name -Description $Description -CreationType WindowsOS
40 |
41 | $SetKeyParams['InputObject'] = $CI
42 | $GetKeyExistanceParams['InputObject'] = $CI
43 |
44 |
45 | foreach ($key in @('Client', 'Server')) {
46 | $currentRegPath = [string]::Format('SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\{0}\{1}', $Protocol, $key)
47 | $SetKeyParams['KeyName'] = $currentRegPath
48 | $GetKeyExistanceParams['KeyName'] = $currentRegPath
49 |
50 | if ($Protocol -in $EnableList) {
51 | $SetKeyParams['Name'] = "Set $Protocol DisabledByDefault for $key to 0"
52 | $SetKeyParams['ExpectedValue'] = 0
53 | $SetKeyParams['RuleName'] = "Set $Protocol DisabledByDefault for $key to 0"
54 | $SetKeyParams['ValueName'] = 'DisabledByDefault'
55 | $SetKeyParams['Description'] = "Set $Protocol DisabledByDefault for $key to 0 to ensure $Protocol is enabled"
56 | $SetKeyParams['RuleDescription'] = "Set $Protocol DisabledByDefault for $key to 0 to ensure $Protocol is enabled"
57 | Add-CMComplianceSettingRegistryKeyValue @SetKeyParams
58 |
59 | $SetKeyParams['Name'] = "Set $Protocol Enabled for $key to 1"
60 | $SetKeyParams['ExpectedValue'] = 1
61 | $SetKeyParams['RuleName'] = "Set $Protocol Enabled for $key to 1"
62 | $SetKeyParams['ValueName'] = 'Enabled'
63 | $SetKeyParams['Description'] = "Set $Protocol Enabled for $key to 1 to ensure $Protocol is enabled"
64 | $SetKeyParams['RuleDescription'] = "Set $Protocol Enabled for $key to 1 to ensure $Protocol is enabled"
65 | Add-CMComplianceSettingRegistryKeyValue @SetKeyParams
66 |
67 | $GetKeyExistanceParams['Name'] = "Validate $Protocol $Key Enabled exists"
68 | $GetKeyExistanceParams['RuleName'] = "Validate $Protocol $Key Enabled exists"
69 | $GetKeyExistanceParams['ValueName'] = 'Enabled'
70 | Add-CMComplianceSettingRegistryKeyValue @GetKeyExistanceParams
71 |
72 | $GetKeyExistanceParams['Name'] = "Validate $Protocol $Key DisabledByDefault exists"
73 | $GetKeyExistanceParams['RuleName'] = "Validate $Protocol $Key DisabledByDefault exists"
74 | $GetKeyExistanceParams['ValueName'] = 'DisabledByDefault'
75 | Add-CMComplianceSettingRegistryKeyValue @GetKeyExistanceParams
76 | }
77 | else {
78 | $SetKeyParams['Name'] = "Set $Protocol DisabledByDefault for $key to 1"
79 | $SetKeyParams['ExpectedValue'] = 1
80 | $SetKeyParams['RuleName'] = "Set $Protocol DisabledByDefault for $key to 1"
81 | $SetKeyParams['ValueName'] = 'DisabledByDefault'
82 | $SetKeyParams['Description'] = "Set $Protocol DisabledByDefault for $key to 1 to ensure $Protocol is disabled"
83 | $SetKeyParams['RuleDescription'] = "Set $Protocol DisabledByDefault for $key to 1 to ensure $Protocol is disabled"
84 | Add-CMComplianceSettingRegistryKeyValue @SetKeyParams
85 |
86 | $SetKeyParams['Name'] = "Set $Protocol Enabled for $key to 0"
87 | $SetKeyParams['ExpectedValue'] = 0
88 | $SetKeyParams['RuleName'] = "Set $Protocol Enabled for $key to 0"
89 | $SetKeyParams['ValueName'] = 'Enabled'
90 | $SetKeyParams['Description'] = "Set $Protocol Enabled for $key to 0 to ensure $Protocol is disabled"
91 | $SetKeyParams['RuleDescription'] = "Set $Protocol Enabled for $key to 0 to ensure $Protocol is disabled"
92 | Add-CMComplianceSettingRegistryKeyValue @SetKeyParams
93 |
94 | $GetKeyExistanceParams['Name'] = "Validate $Protocol $Key Enabled exists"
95 | $GetKeyExistanceParams['RuleName'] = "Validate $Protocol $Key Enabled exists"
96 | $GetKeyExistanceParams['ValueName'] = 'Enabled'
97 | Add-CMComplianceSettingRegistryKeyValue @GetKeyExistanceParams
98 |
99 | $GetKeyExistanceParams['Name'] = "Validate $Protocol $Key DisabledByDefault exists"
100 | $GetKeyExistanceParams['RuleName'] = "Validate $Protocol $Key DisabledByDefault exists"
101 | $GetKeyExistanceParams['ValueName'] = 'DisabledByDefault'
102 | Add-CMComplianceSettingRegistryKeyValue @GetKeyExistanceParams
103 | }
104 | }
105 | Set-CMBaseline -Id $BL.CI_ID -AddOSConfigurationItem $CI.CI_ID
106 | }
107 |
--------------------------------------------------------------------------------
/DB-Size-Queries.sql:
--------------------------------------------------------------------------------
1 | --Queries sourced from various places, just storing them here for easy access.
2 |
3 | -- Table size sorted by total space in MB
4 | SELECT
5 | t.name AS TableName,
6 | i.name as indexName,
7 | sum(p.rows) as RowCounts,
8 | (sum(a.total_pages) * 8) / 1024 as TotalSpaceMB,
9 | (sum(a.used_pages) * 8) / 1024 as UsedSpaceMB,
10 | (sum(a.data_pages) * 8) / 1024 as DataSpaceMB
11 | FROM
12 | sys.tables t
13 | INNER JOIN
14 | sys.indexes i ON t.object_id = i.object_id
15 | INNER JOIN
16 | sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
17 | INNER JOIN
18 | sys.allocation_units a ON p.partition_id = a.container_id
19 | WHERE
20 | t.name NOT LIKE 'dt%' AND
21 | i.object_id > 255 AND
22 | i.index_id <= 1
23 | GROUP BY
24 | t.name, i.object_id, i.index_id, i.name
25 | ORDER BY
26 | 6 DESC
27 |
28 | -- Database file size
29 | SELECT
30 | [TYPE] = A.TYPE_DESC
31 | ,[FILE_Name] = A.name
32 | ,[FILEGROUP_NAME] = fg.name
33 | ,[File_Location] = A.PHYSICAL_NAME
34 | ,[FILESIZE_MB] = CONVERT(DECIMAL(10,2),A.SIZE/128.0)
35 | ,[USEDSPACE_MB] = CONVERT(DECIMAL(10,2),A.SIZE/128.0 - ((SIZE/128.0) - CAST(FILEPROPERTY(A.NAME, 'SPACEUSED') AS INT)/128.0))
36 | ,[FREESPACE_MB] = CONVERT(DECIMAL(10,2),A.SIZE/128.0 - CAST(FILEPROPERTY(A.NAME, 'SPACEUSED') AS INT)/128.0)
37 | ,[FREESPACE_%] = CONVERT(DECIMAL(10,2),((A.SIZE/128.0 - CAST(FILEPROPERTY(A.NAME, 'SPACEUSED') AS INT)/128.0)/(A.SIZE/128.0))*100)
38 | ,[AutoGrow] = 'By ' + CASE is_percent_growth WHEN 0 THEN CAST(growth/128 AS VARCHAR(10)) + ' MB -'
39 | WHEN 1 THEN CAST(growth AS VARCHAR(10)) + '% -' ELSE '' END
40 | + CASE max_size WHEN 0 THEN 'DISABLED' WHEN -1 THEN ' Unrestricted'
41 | ELSE ' Restricted to ' + CAST(max_size/(128*1024) AS VARCHAR(10)) + ' GB' END
42 | + CASE is_percent_growth WHEN 1 THEN ' [autogrowth by percent, BAD setting!]' ELSE '' END
43 | FROM sys.database_files A LEFT JOIN sys.filegroups fg ON A.data_space_id = fg.data_space_id
44 | order by A.TYPE desc, A.NAME;
45 |
46 | -- Index size sorted by total space in kb
47 | SELECT
48 | OBJECT_NAME(i.OBJECT_ID) AS TableName,
49 | i.name AS IndexName,
50 | i.index_id AS IndexID,
51 | 8 * SUM(a.used_pages) AS 'Indexsize(KB)'
52 | FROM
53 | sys.indexes AS i JOIN
54 | sys.partitions AS p ON p.OBJECT_ID = i.OBJECT_ID AND p.index_id = i.index_id JOIN
55 | sys.allocation_units AS a ON a.container_id = p.partition_id
56 | where [i].[is_primary_key] = 0 -- fix for size discrepancy
57 | GROUP BY
58 | i.OBJECT_ID,
59 | i.index_id,
60 | i.name
61 | ORDER BY
62 | 4 DESC
63 |
--------------------------------------------------------------------------------
/Get-30DayHinv_Summary.sql:
--------------------------------------------------------------------------------
1 | SELECT TOP 30
2 | month(lasthw) [Month], day(lasthw) [Day], year(lasthw) [Year], count(*) [Count]
3 | FROM v_r_system_valid sys JOIN
4 | v_ch_clientsummary cs ON sys.resourceid = cs.resourceid
5 | GROUP BY month(lasthw), day(lasthw), year(lasthw)
6 | ORDER BY year(lasthw) DESC, month(lasthw) DESC, day(lasthw) DESC
7 |
--------------------------------------------------------------------------------
/Get-BuzzPhrase.ps1:
--------------------------------------------------------------------------------
1 | function Get-BuzzPhrase {
2 | $Page = invoke-webrequest -uri https://www.atrixnet.com/bs-generator.html
3 | $(foreach ($WordType in @('adverbs', 'verbs', 'adjectives', 'nouns')) {
4 | ([regex]::match(($Page.AllElements)[1].outerHTML, "var $WordType = new Array \(([^\)]+)\)") -replace "var $WordType = new Array \(|\)" -split ',' -replace '''' -replace "`n").Trim() | Get-Random
5 | }) -join ' '
6 | }
7 |
--------------------------------------------------------------------------------
/Get-CMSoftwareUpdatePointSummary.ps1:
--------------------------------------------------------------------------------
1 | function Get-CMSoftwareUpdatePointSummary {
2 | param (
3 | [Parameter(Mandatory = $true)]
4 | [string]$SMSProvider
5 | )
6 | $SiteCode = $(Get-WmiObject -ComputerName $SMSProvider -Namespace 'root/SMS' -Class SMS_ProviderLocation -ErrorAction SilentlyContinue).SiteCode
7 | $WMIQueryParameters = @{
8 | ComputerName = $SMSProvider
9 | NameSpace = "root\sms\site_$SiteCode"
10 | }
11 |
12 | $SoftwareUpdatePoints = Get-WmiObject -Query "SELECT NetbiosName FROM SMS_R_System where SystemRoles = 'SMS Software Update Point'" @WMIQueryParameters | Select-Object -ExpandProperty NetbiosName
13 | $SoftwareUpdatePoints | ForEach-Object {
14 | $ServerName = $_ -replace "\\"
15 | $ServerName = [system.net.dns]::GetHostByName($ServerName).HostNAme
16 | if (Test-Connection -ComputerName $ServerName -Quiet -Count 3) {
17 | $WSUS = @{ }
18 | $WSUS.ComputerName = $ServerName
19 | $WSUS.Site = $SiteCode
20 | $HKLM = 2147483650
21 | $WSUSConfigKeyPath = "SOFTWARE\Microsoft\Update Services\Server\Setup"
22 | $ConnectionProperties = @('PortNumber', 'UsingSSL')
23 | $WMI_Connection = Get-WmiObject -List "StdRegProv" -namespace root\default -ComputerName $ServerName
24 | foreach ($Property in $ConnectionProperties) {
25 | $WSUS.$Property = ($WMI_Connection.GetDWORDValue($hklm, $WSUSConfigKeyPath, $Property)).uValue
26 | }
27 | $WSUS_Server = Get-WsusServer -Name $WSUS['ComputerName'] -UseSsl:$WSUS['UsingSSL'] -PortNumber $WSUS['PortNumber']
28 | $ServerConfig = $WSUS_Server.GetConfiguration()
29 | $DBConfig = $WSUS_Server.GetDatabaseConfiguration()
30 | $WSUS.SyncFromMicrosoftUpdate = $ServerConfig.SyncFromMicrosoftUpdate
31 | if (-not $WSUS.SyncFromMicrosoftUpdate) {
32 | $WSUS.UpstreamWsusServerName = $ServerConfig.UpstreamWsusServerName
33 | $WSUS.UpstreamWsusServerPortNumber = $ServerConfig.UpstreamWsusServerPortNumber
34 | $WSUS.UpstreamWsusServerUseSsl = $ServerConfig.UpstreamWsusServerUseSsl
35 | $WSUS.IsReplicaServer = $ServerConfig.IsReplicaServer
36 | }
37 | $WSUS.PortNumber = $WSUS_Server.PortNumber
38 | $WSUS.SqlServerName = $DBConfig.ServerName
39 | $WSUS.SqlDatabaseName = $DBConfig.DatabaseName
40 | $WSUS.UsingWID = $DBConfig.IsUsingWindowsInternalDatabase
41 | $WSUS.LocalContentCachePath = $ServerConfig.LocalContentCachePath
42 | $WSUS.SyncFromMicrosoftUpdate = $ServerConfig.SyncFromMicrosoftUpdate
43 | [pscustomobject]$WSUS | Select-Object -Property ComputerName, Site, PortNumber, UsingSSL, SqlServerName, SqlDatabaseName, UsingWID, LocalContentCachePath, SyncFromMicrosoftUpdate, UpstreamWsusServerName, UpstreamWsusServerPortNumber, UpstreamWsusServerUseSsl, IsReplicaServer
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Get-HinvFrequency.sql:
--------------------------------------------------------------------------------
1 | /*
2 | This query will show you the count of records per Hardware Inventory class in your HinvChangeLog table.
3 | This can help you identify a class that is create a lot of hardware inventory 'traffic' and potentially bloating
4 | your database.
5 | */
6 | SELECT map.DisplayName
7 | , map.InvClassName AS 'Inventory View'
8 | , COUNT(HINV.RecordID)
9 | FROM HinvChangeLog hinv
10 | LEFT JOIN v_GroupMap map ON map.GroupID = hinv.GroupKey
11 | GROUP BY map.DisplayName
12 | , map.InvClassName
13 | ORDER BY 3 DESC
14 |
--------------------------------------------------------------------------------
/Get-PendingSCCMPatches.ps1:
--------------------------------------------------------------------------------
1 | function Get-PendingSCCMPatches {
2 | [cmdletbinding()]
3 | param(
4 | # Computername(s) to invoke updates on
5 | [parameter(Mandatory = $false, ValueFromPipelineByPropertyName)]
6 | [Alias('Computer', 'PSComputerName', 'IPAddress', 'ServerName', 'HostName')]
7 | [string[]]$ComputerName = $env:COMPUTERNAME,
8 | # switch to determine if Definition updates should be included
9 | [switch]$IncludeDefs,
10 | # Credential to use
11 | [parameter(Mandatory = $false)]
12 | [system.management.automation.pscredential]$Credential
13 | )
14 | begin {
15 | $UpdateStatus = @{
16 | "23" = "WaitForOrchestration";
17 | "22" = "WaitPresModeOff";
18 | "21" = "WaitingRetry";
19 | "20" = "PendingUpdate";
20 | "19" = "PendingUserLogoff";
21 | "18" = "WaitUserReconnect";
22 | "17" = "WaitJobUserLogon";
23 | "16" = "WaitUserLogoff";
24 | "15" = "WaitUserLogon";
25 | "14" = "WaitServiceWindow";
26 | "13" = "Error";
27 | "12" = "InstallComplete";
28 | "11" = "Verifying";
29 | "10" = "WaitReboot";
30 | "9" = "PendingHardReboot";
31 | "8" = "PendingSoftReboot";
32 | "7" = "Installing";
33 | "6" = "WaitInstall";
34 | "5" = "Downloading";
35 | "4" = "PreDownload";
36 | "3" = "Detecting";
37 | "2" = "Submitted";
38 | "1" = "Available";
39 | "0" = "None";
40 | }
41 | #$UpdateStatus.Get_Item("$EvaluationState")
42 | #endregion status type hashtable
43 |
44 | $Filter = switch ($IncludeDefs) {
45 | $true {
46 | "ComplianceState=0"
47 | }
48 | Default {
49 | "NOT Name LIKE '%Definition%' and ComplianceState=0"
50 | }
51 | }
52 | }
53 | process {
54 | foreach ($Computer in $ComputerName) {
55 | try {
56 | if (Test-Connection -ComputerName $Computer -Count 1 -Quiet) {
57 | $getWmiObjectSplat = @{
58 | Filter = $Filter
59 | ComputerName = $Computer
60 | Namespace = 'root\CCM\ClientSDK'
61 | Class = 'CCM_SoftwareUpdate'
62 | }
63 | if ($PSBoundParameters.ContainsKey('Credential')) {
64 | $getWmiObjectSplat.Add('Credential', $Credential)
65 | }
66 | [System.Management.ManagementObject[]]$MissingUpdates = Get-WmiObject @getWmiObjectSplat
67 | if ($MissingUpdates -is [Object] -and $MissingUpdates.Count -gt 0) {
68 | $MissingUpdates
69 | }
70 | else {
71 | Write-Verbose "No updates found for $Computer"
72 | }
73 | }
74 | else {
75 | Write-Warning "$Computer is not online"
76 | }
77 | }
78 | catch {
79 | $ErrorMessage = $_.Exception.Message
80 | Write-Error $ErrorMessage
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Get-SupersededUpdatesInSUGBySUG.ps1:
--------------------------------------------------------------------------------
1 | param(
2 | [Parameter(Mandatory = $true)]
3 | [string]$SoftwareUpdateGroupName
4 | )
5 | # return a list of updates which are superseded by another update in the same SUG
6 | $SUG = Get-CMSoftwareUpdateGroup -Name $SoftwareUpdateGroupName
7 | $allInSUG = Get-CMSoftwareUpdate -UpdateGroup $SUG
8 | $updatesSugSupersedes = foreach ($Updates in $allInSUG) {
9 | ([xml]$Updates.sdmpackagexml).GetElementsByTagName("SupersededUpdates").SoftwareUpdateReference.LogicalName
10 | }
11 | return $allInSUG.Where( { [string]::Format("SUM_{0}", $_.CI_UniqueID) -in $updatesSugSupersedes })
12 |
--------------------------------------------------------------------------------
/Get-WQLObject.ps1:
--------------------------------------------------------------------------------
1 | param(
2 | # WQL formatted query to perform
3 | [Parameter(Mandatory = $true, ParameterSetName = 'CustomQuery')]
4 | [string]
5 | $Query,
6 | # SMS Provider to query against
7 | [Parameter(Mandatory = $true)]
8 | [string]
9 | $SMSProvider,
10 | # Optional PSCredential (unfortunately I can't figure out how to use this cred in the DynamicParam WMI queries without providing info outside the function)
11 | [Parameter(Mandatory = $false, ParameterSetName = 'CustomQuery')]
12 | [pscredential]
13 | $Credential
14 | )
15 | DynamicParam {
16 | if (($SMSProvider = $PSBoundParameters['SMSProvider'])) {
17 | $ParameterName = 'SCCMQuery'
18 | $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
19 | $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
20 | $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
21 | $ParameterAttribute.Mandatory = $true
22 | $ParameterAttribute.ParameterSetName = 'ExistingQuery'
23 | $ParameterAttribute.HelpMessage = 'Specify the name of a query that already exists in your ConfigMgr environment'
24 | $AttributeCollection.Add($ParameterAttribute)
25 | $SiteCode = (Get-WmiObject -Namespace "root\sms" -ClassName "__Namespace" -ComputerName $SMSProvider).Name.Substring(5, 3)
26 | $Namespace = [string]::Format("root\sms\site_{0}", $SiteCode)
27 | $arrSet = Get-WmiObject -ComputerName $SMSProvider -Namespace $Namespace -Query "SELECT Name FROM SMS_Query WHERE Expression not like '%##PRM:%'" | Select-Object -ExpandProperty Name
28 | $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)
29 | $AttributeCollection.Add($ValidateSetAttribute)
30 | $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
31 | $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
32 | return $RuntimeParameterDictionary
33 | }
34 | }
35 | Begin {
36 | $SCCMQuery = $PsBoundParameters[$ParameterName]
37 | if ($PSBoundParameters.ContainsKey('Credential') -and -not $PSDefaultParameterValues.ContainsKey("Get-WmiObject:Credential")) {
38 | $AddedDefaultParam = $true
39 | $PSDefaultParameterValues.Add("Get-WmiObject:Credential", $Credential)
40 | }
41 | $SiteCode = (Get-WmiObject -Namespace "root\sms" -ClassName "__Namespace" -ComputerName $SMSProvider).Name.Substring(5, 3)
42 | $Namespace = [string]::Format("root\sms\site_{0}", $SiteCode)
43 | if ($PSCmdlet.ParameterSetName -eq 'ExistingQuery') {
44 | $Query = Get-WmiObject -ComputerName $SMSProvider -Namespace $Namespace -Query "SELECT Expression FROM SMS_Query WHERE Name ='$SCCMQuery'" | Select-Object -ExpandProperty Expression
45 | }
46 | }
47 | Process {
48 | $RawResults = Get-WmiObject -ComputerName $SMSProvider -Namespace $Namespace -Query $Query
49 | $PropertySelectors = $RawResults | Get-Member -MemberType Property | Where-Object { -not $_.Name.StartsWith('__') } | Select-Object -ExpandProperty name | ForEach-Object {
50 | $Class = $_
51 | $Properties = $RawResults.$Class | Get-Member -MemberType Property | Where-Object { -not $_.Name.StartsWith('__') } | Select-Object -ExpandProperty name
52 | foreach ($Property in $Properties) {
53 | [string]::Format("@{{Label='{1}.{0}';Expression = {{`$_.{1}.{0}}}}}", $Property, $Class)
54 | }
55 | }
56 | }
57 | end {
58 | if ($AddedDefaultParam) {
59 | $PSDefaultParameterValues.Remove("Get-WmiObject:Credential")
60 | }
61 | $PropertySelector = [scriptblock]::Create($($PropertySelectors -join ','))
62 | $RawResults | Select-Object -Property $(. $PropertySelector)
63 | }
64 |
--------------------------------------------------------------------------------
/Invoke-SCCMUpdates.ps1:
--------------------------------------------------------------------------------
1 | function Invoke-SCCMUpdates {
2 | param(
3 | # Computername(s) to invoke updates on
4 | [parameter(Mandatory = $false, ValueFromPipelineByPropertyName)]
5 | [Alias('Computer', 'PSComputerName', 'IPAddress')]
6 | [string[]]$ComputerName = $env:COMPUTERNAME,
7 | # switch to determine if Definition updates should be included
8 | [parameter(Mandatory = $false)]
9 | [switch]$IncludeDefs,
10 | # invoke a set of updates
11 | [parameter(Mandatory = $false, ParameterSetName = 'PassUpdates', ValueFromPipeline)]
12 | [System.Management.ManagementObject[]]$Updates,
13 | # Credential to use
14 | [parameter(Mandatory = $false)]
15 | [pscredential]$Credential
16 | )
17 | begin {
18 | $UpdateStatus = @{
19 | "23" = "WaitForOrchestration";
20 | "22" = "WaitPresModeOff";
21 | "21" = "WaitingRetry";
22 | "20" = "PendingUpdate";
23 | "19" = "PendingUserLogoff";
24 | "18" = "WaitUserReconnect";
25 | "17" = "WaitJobUserLogon";
26 | "16" = "WaitUserLogoff";
27 | "15" = "WaitUserLogon";
28 | "14" = "WaitServiceWindow";
29 | "13" = "Error";
30 | "12" = "InstallComplete";
31 | "11" = "Verifying";
32 | "10" = "WaitReboot";
33 | "9" = "PendingHardReboot";
34 | "8" = "PendingSoftReboot";
35 | "7" = "Installing";
36 | "6" = "WaitInstall";
37 | "5" = "Downloading";
38 | "4" = "PreDownload";
39 | "3" = "Detecting";
40 | "2" = "Submitted";
41 | "1" = "Available";
42 | "0" = "None";
43 | }
44 | #$UpdateStatus.Get_Item("$EvaluationState")
45 | #endregion status type hashtable
46 |
47 | $Filter = switch ($IncludeDefs) {
48 | $true {
49 | "ComplianceState=0"
50 | }
51 | Default {
52 | "NOT Name LIKE '%Definition%' and ComplianceState=0"
53 | }
54 | }
55 | }
56 | process {
57 | foreach ($Computer in $ComputerName) {
58 | try {
59 | if (Test-Connection -ComputerName $Computer -Count 1 -Quiet) {
60 | if ($PSCmdlet.ParameterSetName -eq 'PassUpdates') {
61 | $invokeWmiMethodSplat = @{
62 | Namespace = 'root\ccm\clientsdk'
63 | ArgumentList = ( , $Updates)
64 | ComputerName = $Computer
65 | Name = 'InstallUpdates'
66 | Class = 'CCM_SoftwareUpdatesManager'
67 | }
68 | if ($PSBoundParameters.ContainsKey('Credential')) {
69 | $invokeWmiMethodSplat.Add('Credential', $Credential)
70 | }
71 | Invoke-WmiMethod @invokeWmiMethodSplat
72 | }
73 | else {
74 | $getWmiObjectSplat = @{
75 | Filter = $Filter
76 | ComputerName = $Computer
77 | Namespace = 'root\CCM\ClientSDK'
78 | Class = 'CCM_SoftwareUpdate'
79 | }
80 | if ($PSBoundParameters.ContainsKey('Credential')) {
81 | $getWmiObjectSplat.Add('Credential', $Credential)
82 | }
83 | [System.Management.ManagementObject[]]$MissingUpdates = Get-WmiObject @getWmiObjectSplat
84 | if ($MissingUpdates -is [Object]) {
85 | $invokeWmiMethodSplat = @{
86 | Namespace = 'root\ccm\clientsdk'
87 | ArgumentList = ( , $MissingUpdates)
88 | ComputerName = $Computer
89 | Name = 'InstallUpdates'
90 | Class = 'CCM_SoftwareUpdatesManager'
91 | }
92 | if ($PSBoundParameters.ContainsKey('Credential')) {
93 | $invokeWmiMethodSplat.Add('Credential', $Credential)
94 | }
95 | Invoke-WmiMethod @invokeWmiMethodSplat
96 | }
97 | else {
98 | Write-Output "$Computer has no updates available to invoke"
99 | }
100 | }
101 | }
102 | else {
103 | Write-Warning "$Computer is not online"
104 | }
105 | }
106 | catch {
107 | $ErrorMessage = $_.Exception.Message
108 | Write-Error $ErrorMessage
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Invoke-SQLAGPatchPrep.ps1:
--------------------------------------------------------------------------------
1 | param(
2 | [Parameter(Mandatory = $false)]
3 | [ValidateSet('Drain', 'Resume')]
4 | [string]$Purpose = 'Resume'
5 | )
6 | $AvailabilityGroups = Get-DbaAvailabilityGroup -SqlInstance $env:COMPUTERNAME
7 | foreach ($AG in $AvailabilityGroups) {
8 | $DatabaseName = $AG.AvailabilityDatabases.Name
9 | $AGName = $AG.AvailabilityGroup
10 | $AGListener = $AG.AvailabilityGroupListeners.Name
11 | $PrimaryNode = $AG.PrimaryReplica
12 |
13 | $CheckAG = @"
14 | SELECT name AS [AGname]
15 | , replica_server_name AS [ServerName]
16 | , CASE
17 | WHEN replica_server_name=ag.primary_replica THEN 'PRIMARY'
18 | ELSE 'SECONDARY'
19 | END AS [Status]
20 | , synchronization_health_desc AS [SynchronizationHealth]
21 | , failover_mode_desc AS [FailoverMode]
22 | , availability_mode AS [Synchronous]
23 | , secondary_role_allow_connections_desc [ReadableSecondary]
24 | FROM sys.availability_replicas r
25 | INNER JOIN sys.availability_groups g ON r.group_id = g.group_id
26 | LEFT JOIN master.sys.dm_hadr_availability_group_states ag ON r.group_id = ag.group_id
27 | "@
28 |
29 |
30 | switch ($Purpose) {
31 | 'Drain' {
32 | try {
33 | $StartStateAG = Invoke-DbaQuery -SqlInstance $AGListener -Query $CheckAG -ErrorAction Stop
34 | $SecondaryNode = $StartStateAG | Where-Object { $_.Status -eq 'SECONDARY' } | Select-Object -ExpandProperty ServerName
35 | }
36 | catch {
37 | Write-Error 'Failed to query for Availability Group status'
38 | exit 1
39 | }
40 |
41 | switch ($StartStateAG.SynchronizationHealth) {
42 | 'HEALTHY' {
43 | continue;
44 | }
45 | default {
46 | Write-Error 'At least one node has unhealthy SynchronizationHealth'
47 | exit 1
48 | }
49 | }
50 |
51 | switch ($StartStateAG) {
52 | { $_.FailoverMode -ne 'MANUAL' } {
53 | Set-DbaAgReplica -SqlInstance $PrimaryNode -AvailabilityGroup $_.AGname -Replica $_.ServerName -FailoverMode Manual
54 | }
55 | }
56 |
57 | switch ($PrimaryNode -eq $env:COMPUTERNAME) {
58 | $true {
59 | Invoke-DbaAgFailover -SqlInstance $SecondaryNode -AvailabilityGroup $AGName -Force
60 | }
61 | }
62 |
63 | Suspend-DbaAgDbDataMovement -SqlInstance $env:COMPUTERNAME -AvailabilityGroup $AGName -Database $DatabaseName -Confirm:$false
64 |
65 | $ClusterStatus = Get-ClusterNode -Name $env:COMPUTERNAME
66 | switch ($ClusterStatus.State) {
67 | 'Up' {
68 | Suspend-ClusterNode -Wait -Drain
69 | }
70 | }
71 | }
72 | 'Resume' {
73 | $PrimaryNode = $AG.PrimaryReplica
74 | $ClusterStatus = Get-ClusterNode -Name $env:COMPUTERNAME
75 | switch ($ClusterStatus.State) {
76 | 'Up' {
77 | continue
78 | }
79 | default {
80 | Resume-ClusterNode -Name $env:COMPUTERNAME
81 | }
82 | }
83 | foreach ($Node in $AG.AvailabilityReplicas.Name) {
84 | Set-DbaAgReplica -SqlInstance $PrimaryNode -AvailabilityGroup $AG.AvailabilityGroup -Replica $Node -FailoverMode Automatic
85 | }
86 |
87 | Resume-DbaAgDbDataMovement -SqlInstance $env:COMPUTERNAME -AvailabilityGroup $AG.AvailabilityGroup -Database $AG.AvailabilityDatabases.Name -Confirm:$false
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/Invoke-UpdateScanAfterSSU/CI - Invoke-UpdateScanAfterSSU - Scheduled Task.cab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodyMathis123/CM-Ramblings/ed952ee8966a9914ba5bff976020b5f16c20758f/Invoke-UpdateScanAfterSSU/CI - Invoke-UpdateScanAfterSSU - Scheduled Task.cab
--------------------------------------------------------------------------------
/Invoke-UpdateScanAfterSSU/Invoke-UpdateScanAfterSSU.ps1:
--------------------------------------------------------------------------------
1 | #region detection
2 | $TaskName = 'Invoke-UpdateScanAfterSSU'
3 |
4 | $Task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
5 |
6 | $null -ne $Task
7 | #endregion detection
8 |
9 | #region remediation
10 | $TaskName = 'Invoke-UpdateScanAfterSSU'
11 |
12 | $TaskXML = @"
13 |
14 |
16 |
17 | 2019-05-22T23:53:35.7629665
18 | SCCM
19 | \$TaskName
20 |
21 |
22 |
23 |
24 | PT5M
25 | PT15M
26 | true
27 |
28 | PT30M
29 | true
30 | <QueryList><Query Id="0" Path="System"><Select Path="System">*[System[Provider[@Name='Microsoft-Windows-WindowsUpdateClient'] and EventID=19]]</Select></Query></QueryList>
31 | PT1M
32 |
33 |
34 |
35 |
36 | S-1-5-18
37 | LeastPrivilege
38 |
39 |
40 |
41 | IgnoreNew
42 | true
43 | true
44 | true
45 | false
46 | false
47 |
48 | true
49 | false
50 |
51 | true
52 | true
53 | false
54 | false
55 | false
56 | PT72H
57 | 7
58 |
59 |
60 |
61 | C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
62 | -command "&{`$TimeFrame=(Get-Date).AddMinutes(-17);`$Filter=@{LogName='System';StartTime=`$TimeFrame;Id='19';ProviderName='Microsoft-Windows-WindowsUpdateClient';};`$Events=Get-WinEvent -FilterHashtable `$Filter;foreach(`$Event in `$Events){switch -Regex (`$Event.Message){'Servicing Stack Update'{foreach(`$Schedule in @('108','113')){`$ScheduleString = [string]::Format('{{00000000-0000-0000-0000-000000000{0}}}',`$Schedule);`$invokeWmiMethodSplat=@{Name='TriggerSchedule';Namespace='root\ccm';Class='sms_client';ArgumentList=`$ScheduleString;ErrorAction='Stop';};Invoke-WmiMethod @invokeWmiMethodSplat;}}}}}"
63 |
64 |
65 |
66 | "@
67 |
68 | Register-ScheduledTask -Xml $TaskXML -TaskName $TaskName
69 | #endregion remediation
70 |
--------------------------------------------------------------------------------
/Invoke-UpdateScanAfterSSU/readme.md:
--------------------------------------------------------------------------------
1 | https://sccmf12twice.com/2019/05/the-cure-for-your-ssu-fever/
2 |
--------------------------------------------------------------------------------
/MEMCM_PolicyPriority/README.md:
--------------------------------------------------------------------------------
1 | #### MEMCM Policy Priority
2 |
3 | If you have ever been in an environment with even a handful of AV Policies, or Client Settings policies in MEMCM then you have felt the pain of clicking increase, or decrease over and over to appropriately set policy priority.
4 |
5 | In this folder you'll find a couple quick functions to simplify setting the priority of a MEMCM Antimalware Policy, or Client Settings policy. Each functions supports -Verbose, and -WhatIf. An example of using each of them is below.
6 |
7 | ```ps
8 | Set-CMAntimalwarePolicyPriority -Name AVPolicy1 -Priority 3
9 | Set-CMClientSettingPriority -Name ClientSettings1 -Priority 1
10 | ```
11 |
12 | Whether the priority needs to increase, or decrease is handled automatically. You simply provide the desired priority and the let the function do the rest!
13 |
14 | They could be improved by adding pipeline support from the builtin Get-CM* cmdlets for the respective types.... feel free to add a pull request :)
15 |
--------------------------------------------------------------------------------
/MEMCM_PolicyPriority/Set-CMAntimalwarePolicyPriority.ps1:
--------------------------------------------------------------------------------
1 | function Set-CMAntimalwarePolicyPriority {
2 | <#
3 | .SYNOPSIS
4 | Move a MEMCM Antimalware policy to the specified priority
5 | .DESCRIPTION
6 | Becuase the GUI does not allow you to move more than one step at a time,
7 | this PowerShell function can be used to set an Antimalware policy to a specific
8 | priority without having to click increase, or decrease over and over
9 | .PARAMETER Name
10 | The name of the Antimalware Policy to increase or decrease the priority of
11 | .PARAMETER Priority
12 | The desired priority to set the Antimalware Policy to
13 | .EXAMPLE
14 | PS C:\> Set-CMAntimalwarePolicyPriority -Name 'AVPolicy1' -Priority 3
15 | Will move the priority of the AVPolicy1 up, or down, until it reaches priority 3
16 | .NOTES
17 | FileName: Set-CMAntimalwarePolicyPriority.ps1
18 | Author: Cody Mathis
19 | Contact: @CodyMathis123
20 | Created: 2020-07-07
21 | Updated: 2020-07-07
22 | #>
23 | [CmdletBinding(SupportsShouldProcess = $true)]
24 | param (
25 | [Parameter(Mandatory = $true)]
26 | [string]$Name,
27 | [Parameter(Mandatory = $true)]
28 | [int]$Priority
29 | )
30 | $Policy = Get-CMAntimalwarePolicy -Name $Name
31 | if ($null -eq $Policy) {
32 | Write-Warning "No AntiMalware policy found with [Name: $Name]"
33 | return $false
34 | }
35 | $BeginningPriority = $Policy.Priority
36 |
37 | if ($BeginningPriority -eq $Priority) {
38 | Write-Verbose "Policy [Name: $Name] found with [Priority: $BeginningPriority] already set"
39 | return $true
40 | }
41 | else {
42 | Write-Verbose "Policy [Name: $Name] found with [Priority: $BeginningPriority] - will increase or decrease as needed"
43 |
44 | switch ($Priority -gt $BeginningPriority) {
45 | $true {
46 | Write-Verbose "Will Decrease policy priority until it reaches $Priority"
47 | if ($PSCmdlet.ShouldProcess("[PolicyName: $Name] [DesiredPriority: $Priority] [Action: Decrease]", "Set-CMAntimalwarePolicyPriority")) {
48 |
49 | Do {
50 | $Policy | Set-CMAntimalwarePolicy -Priority Decrease
51 | }
52 | until ((Get-CMAntimalwarePolicy -Name $Name).Priority -eq $Priority)
53 | }
54 | }
55 | $false {
56 | Write-Verbose "Will Increase policy priority until it reaches $Priority"
57 | if ($PSCmdlet.ShouldProcess("[PolicyName: $Name] [DesiredPriority: $Priority] [Action: Increase]", "Set-CMAntimalwarePolicyPriority")) {
58 |
59 | Do {
60 | $Policy | Set-CMAntimalwarePolicy -Priority Increase
61 | }
62 | until ((Get-CMAntimalwarePolicy -Name $Name).Priority -eq $Priority)
63 | }
64 | }
65 | }
66 |
67 | $EndPriority = (Get-CMAntimalwarePolicy -Name $Name).Priority
68 | if ($EndPriority -eq $Priority) {
69 | return $true
70 | }
71 | else {
72 | return $false
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/MEMCM_PolicyPriority/Set-CMClientSettingPriority.ps1:
--------------------------------------------------------------------------------
1 | function Set-CMClientSettingPriority {
2 | <#
3 | .SYNOPSIS
4 | Move a MEMCM Client policy to the specified priority
5 | .DESCRIPTION
6 | Becuase the GUI does not allow you to move more than one step at a time,
7 | this PowerShell function can be used to set an Client Settings policy to a specific
8 | priority without having to click increase, or decrease over and over
9 | .PARAMETER Name
10 | The name of the Client Policy to increase or decrease the priority of
11 | .PARAMETER Priority
12 | The desired priority to set the Client Policy to
13 | .EXAMPLE
14 | PS C:\> Set-CMClientSettingPriority -Name 'ClientSetting1' -Priority 3
15 | Will move the priority of the ClientSetting1 up, or down, until it reaches priority 3
16 | .NOTES
17 | FileName: Set-CMClientSettingPriority.ps1
18 | Author: Cody Mathis
19 | Contact: @CodyMathis123
20 | Created: 2020-07-07
21 | Updated: 2020-07-07
22 | #>
23 | [CmdletBinding(SupportsShouldProcess = $true)]
24 | param (
25 | [Parameter(Mandatory = $true)]
26 | [string]$Name,
27 | [Parameter(Mandatory = $true)]
28 | [int]$Priority
29 | )
30 | $Policy = Get-CMClientSetting -Name $Name
31 | if ($null -eq $Policy) {
32 | Write-Warning "No Client policy found with [Name: $Name]"
33 | return $false
34 | }
35 | $BeginningPriority = $Policy.Priority
36 |
37 | if ($BeginningPriority -eq $Priority) {
38 | Write-Verbose "Policy [Name: $Name] found with [Priority: $BeginningPriority] already set"
39 | return $true
40 | }
41 | else {
42 | Write-Verbose "Policy [Name: $Name] found with [Priority: $BeginningPriority] - will increase or decrease as needed"
43 |
44 | switch ($Priority -gt $BeginningPriority) {
45 | $true {
46 | Write-Verbose "Will Decrease policy priority until it reaches $Priority"
47 | if ($PSCmdlet.ShouldProcess("[PolicyName: $Name] [DesiredPriority: $Priority] [Action: Decrease]", "Set-CMClientSettingPriority")) {
48 |
49 | Do {
50 | $Policy | Set-CMClientSettingGeneral -Priority Decrease
51 | }
52 | until ((Get-CMClientSetting -Name $Name).Priority -eq $Priority)
53 | }
54 | }
55 | $false {
56 | Write-Verbose "Will Increase policy priority until it reaches $Priority"
57 | if ($PSCmdlet.ShouldProcess("[PolicyName: $Name] [DesiredPriority: $Priority] [Action: Increase]", "Set-CMClientSettingPriority")) {
58 |
59 | Do {
60 | $Policy | Set-CMClientSettingGeneral -Priority Increase
61 | }
62 | until ((Get-CMClientSetting -Name $Name).Priority -eq $Priority)
63 | }
64 | }
65 | }
66 |
67 | $EndPriority = (Get-CMClientSetting -Name $Name).Priority
68 | if ($EndPriority -eq $Priority) {
69 | return $true
70 | }
71 | else {
72 | return $false
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/MachineCertInv.ps1:
--------------------------------------------------------------------------------
1 | ## Define new class name and date
2 | $NewClassName = 'Win32_MachineCerts'
3 |
4 | ## Remove class if exists
5 | Remove-WmiObject -Class $NewClassName -ErrorAction SilentlyContinue
6 |
7 | # Create new WMI class
8 | $newClass = New-Object System.Management.ManagementClass ("root\cimv2", [String]::Empty, $null)
9 | $newClass["__CLASS"] = $NewClassName
10 |
11 | ## Create properties you want inventoried
12 | $newClass.Qualifiers.Add("Static", $true)
13 | $newClass.Properties.Add("PSPath", [System.Management.CimType]::String, $false)
14 | $newClass.Properties.Add("PSParentPath", [System.Management.CimType]::String, $false)
15 | $newClass.Properties.Add("Issuer", [System.Management.CimType]::String, $false)
16 | $newClass.Properties.Add("Subject", [System.Management.CimType]::String, $false)
17 | $newClass.Properties.Add("FriendlyName", [System.Management.CimType]::String, $false)
18 | $newClass.Properties.Add("Version", [System.Management.CimType]::String, $false)
19 | $newClass.Properties.Add("Thumbprint", [System.Management.CimType]::String, $false)
20 | $newClass.Properties.Add("NotAfter", [System.Management.CimType]::String, $false)
21 | $newClass.Properties.Add("NotBefore", [System.Management.CimType]::String, $false)
22 | $newClass.Properties.Add("DNSNameList", [System.Management.CimType]::String, $false)
23 | $newClass.Properties["PSPath"].Qualifiers.Add("Key", $true)
24 | $newClass.Put() | Out-Null
25 |
26 | ## Gather current cert information
27 | Get-ChildItem Cert:\LocalMachine -Recurse | Where-Object { $_.PSisContainer -eq $false } | Select-Object PSPath, PSparentpath, Issuer, Subject, FriendlyName, Version, Thumbprint, NotAfter, NotBefore, DNSNamelist |
28 | ForEach-Object {
29 |
30 | ## Set cert information in new class
31 | Set-WmiInstance -Namespace root\cimv2 -class $NewClassName -ErrorAction SilentlyContinue -Arguments @{
32 | PSParentPath = $_.PSParentPath
33 | Issuer = $_.Issuer
34 | Subject = $_.Subject
35 | FriendlyName = $_.FriendlyName
36 | Version = $_.Version
37 | Thumbprint = $_.Thumbprint
38 | NotAfter = $_.NotAfter
39 | NotBefore = $_.NotBefore
40 | DNSNamelist = $_.DNSNamelist
41 | PSPath = $_.PSPath
42 | } | Out-Null
43 | }
44 |
45 | Write-Output "Complete"
46 |
--------------------------------------------------------------------------------
/New-CMScheduleStartTime.ps1:
--------------------------------------------------------------------------------
1 | Function New-CMScheduleStartTime {
2 | [CmdletBinding()]
3 | <#
4 | .SYNOPSIS
5 | Recreate a CMSchedule object with a new start time
6 | .DESCRIPTION
7 | Natively, the CMSchedule objects do not allow you to write to the StartTime property. This makes it
8 | difficult to adjust the start time of an existing maintenance window. This function can be used to
9 | 'recreate' a CMSchedule based on the input schedule, with a new start time.
10 | .PARAMETER CMSchedule
11 | An array of CMSchedule objects
12 | .PARAMETER StartTime
13 | The desired new start time for the schedule
14 | .EXAMPLE
15 | CCM:\> $Sched = Get-CMMaintenanceWindow -CollectionName 'test'
16 | $Schedobject = Convert-CMSchedule -ScheduleString $Sched.ServiceWindowSchedules
17 | New-CMScheduleStartTime -CMSchedule $Schedobject -StartTime $Schedobject.StartTime.AddDays(5)
18 | .NOTES
19 | FileName: New-CMScheduleStartTime.ps1
20 | Author: Cody Mathis
21 | Contact: @CodyMathis123
22 | Created: 2020-02-26
23 | Updated: 2020-02-26
24 | #>
25 | Param(
26 | [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
27 | [Alias('Schedules')]
28 | [Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlResultObjectBase[]]$CMSchedule,
29 | [Parameter(Mandatory = $true)]
30 | [datetime]$StartTime
31 | )
32 | begin {
33 | #region create our splat for the new schedule, start time is the same for all
34 | $NewSchedSplat = @{
35 | Start = $StartTime
36 | }
37 | #endregion create our splat for the new schedule, start time is the same for all
38 | }
39 | process {
40 | foreach ($Schedule in $CMSchedule) {
41 | #region determine new end time based off new start time, and existing durations
42 | $NewEndTime = $StartTime.AddDays($Schedule.DayDuration).AddHours($Schedule.HourDuration).AddMinutes($Schedule.MinuteDuration)
43 | #endregion determine new end time based off new start time, and existing durations
44 |
45 | #region define the paramters that are the same for all 'new' schedules
46 | $NewSchedSplat['End'] = $NewEndTime
47 | $NewSchedSplat['IsUTC'] = $Schedule.IsGMT
48 | #endregion define the paramters that are the same for all 'new' schedules
49 |
50 | try {
51 | #region based on recur type, we will add parameters to our $NewSchedSplat
52 | Switch ($Schedule.SmsProviderObjectPath) {
53 | SMS_ST_NonRecurring {
54 | $NewSchedSplat['Nonrecurring'] = $true
55 | }
56 | SMS_ST_RecurInterval {
57 | if ($Schedule.MinuteSpan -ne 0) {
58 | $Span = 'Minutes'
59 | $Interval = $Schedule.MinuteSpan
60 | }
61 | elseif ($Schedule.HourSpan -ne 0) {
62 | $Span = 'Hours'
63 | $Interval = $Schedule.HourSpan
64 | }
65 | elseif ($Schedule.DaySpan -ne 0) {
66 | $Span = 'Days'
67 | $Interval = $Schedule.DaySpan
68 | }
69 | $NewSchedSplat['RecurInterval'] = $Span
70 | $NewSchedSplat['RecurCount'] = $Interval
71 | }
72 | SMS_ST_RecurWeekly {
73 | $NewSchedSplat['DayOfWeek'] = [DayOfWeek]($Day - $Schedule.Day)
74 | $NewSchedSplat['RecurCount'] = $Schedule.ForNumberOfWeeks
75 | }
76 | SMS_ST_RecurMonthlyByWeekday {
77 | $NewSchedSplat['DayOfWeek'] = [DayOfWeek]($Day - $Schedule.Day)
78 | $NewSchedSplat['WeekOrder'] = $Schedule.WeekOrder
79 | $NewSchedSplat['RecurCount'] = $Schedule.ForNumberOfMonths
80 | }
81 | SMS_ST_RecurMonthlyByDate {
82 | $NewSchedSplat['DayOfMonth'] = $Schedule.MonthDay
83 | $NewSchedSplat['RecurCount'] = $Schedule.ForNumberOfMonths
84 | }
85 | Default {
86 | Write-Error "Parsing Schedule String resulted in invalid type of $RecurType" -ErrorAction Stop
87 | }
88 | }
89 | #endregion based on recur type, we will add parameters to our $NewSchedSplat
90 |
91 | #region return our new CMSchedule
92 | New-CMSchedule @NewSchedSplat
93 | #endregion return our new CMSchedule
94 | }
95 | Catch {
96 | $_.Exception.Message
97 | }
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/New-PostTeamsMachineWideInstallScheduledTask.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | Launch the Teams install as the logged in user via a scheduled task
4 | .DESCRIPTION
5 | This script will create a scheduled task if one is not found which is used to
6 | install Microsoft Teams as the logged in user. This scheduled task executes
7 | the Teams.exe found in %ProgramFiles% so that a user can start using Teams
8 | shortly after the Machine Wide installer completes instead of having to
9 | log off and back on.
10 | .NOTES
11 | Generally used as a script that runs after a Teams Machine Wide Installer completes
12 | #>
13 | if (!(Get-ScheduledTask -TaskName 'Teams User Install - Post Machine Wide Install' -ErrorAction SilentlyContinue)) {
14 | switch ([System.Environment]::Is64BitOperatingSystem) {
15 | $true {
16 | [string]$TeamsMachineInstaller = Get-ItemPropertyValue -Path registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run\ -Name TeamsMachineInstaller -ErrorAction Stop
17 | [string]$Exe = $TeamsMachineInstaller.Substring(0, $TeamsMachineInstaller.IndexOf('.exe') + 4).Trim() -Replace "C:\\Program Files\\", "${env:ProgramFiles(x86)}\"
18 |
19 | }
20 | $false {
21 | [string]$TeamsMachineInstaller = Get-ItemPropertyValue -Path registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\ -Name TeamsMachineInstaller -ErrorAction Stop
22 | [string]$Exe = $TeamsMachineInstaller.Substring(0, $TeamsMachineInstaller.IndexOf('.exe') + 4).Trim()
23 | }
24 | }
25 | [string]$InstallerArgs = $TeamsMachineInstaller.Substring($Exe.Length, $TeamsMachineInstaller.Length - $exe.Length).Trim()
26 | $newScheduledTaskSplat = @{
27 | Action = New-ScheduledTaskAction -Execute $Exe -Argument $InstallerArgs
28 | Description = 'Start the Teams installer for the currently logged on user after a Teams Machine Wide install'
29 | Settings = New-ScheduledTaskSettingsSet -Compatibility Vista -AllowStartIfOnBatteries -MultipleInstances IgnoreNew -ExecutionTimeLimit (New-TimeSpan -Hours 1)
30 | Trigger = New-ScheduledTaskTrigger -At ($Start = (Get-Date).AddSeconds(5)) -Once
31 | Principal = New-ScheduledTaskPrincipal -GroupId 'S-1-5-32-545' -RunLevel Limited
32 | }
33 |
34 | $ScheduledTask = New-ScheduledTask @newScheduledTaskSplat
35 | $ScheduledTask.Settings.DeleteExpiredTaskAfter = "PT0S"
36 | $ScheduledTask.Triggers[0].StartBoundary = $Start.ToString("yyyy-MM-dd'T'HH:mm:ss")
37 | $ScheduledTask.Triggers[0].EndBoundary = $Start.AddMinutes(10).ToString('s')
38 |
39 | Register-ScheduledTask -InputObject $ScheduledTask -TaskName 'Teams User Install - Post Machine Wide Install'
40 | }
--------------------------------------------------------------------------------
/Office365/O365-PrjOnline-VisPro-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-PrjOnline-VisPro-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-PrjOnline-VisStd-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-PrjOnline-VisStd-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-PrjOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-PrjPro-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-PrjPro-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-PrjStd-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-PrjStd-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisOnline-PrjOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisOnline-PrjPro-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisOnline-PrjPro-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisOnline-PrjStd-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisOnline-PrjStd-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisPro-2016-PrjOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisPro-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisPro-2019-PrjOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisPro-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisPro-PrjPro-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisPro-PrjPro-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisPro-PrjStd-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisPro-PrjStd-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisStd-2016-PrjOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisStd-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisStd-2019-PrjOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisStd-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisStd-PrjPro-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisStd-PrjPro-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisStd-PrjStd-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365-VisStd-PrjStd-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/O365.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Office365/PrjOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/PrjPro-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/PrjPro-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/PrjStd-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/PrjStd-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/VisOnline.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/VisPro-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/VisPro-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/VisStd-2016.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/VisStd-2019.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Office365/readme.md:
--------------------------------------------------------------------------------
1 | https://sccmf12twice.com/2019/05/getting-from-msi-to-c2r/
2 |
3 | End Product - One application with all possible deployment types that will dynamically install the 'new' version of Office / Project / Visio as needed based on your licensing selection.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | You can place all the XML, and Office 365 c2r setup.exe in a directory.
12 |
13 | You'll want to run:
14 |
15 | setup.exe /download Office365.xml
16 |
17 | Once to get the ball rolling. The binaries are the same for every single app combination.
18 |
19 | The script has 11 parameters that you can see below in the help info from the script.
20 |
21 | .PARAMETER SMSProvider
22 | Provides the name for the SMSProvider for the environment you want to create the application in.
23 | .PARAMETER ApplicationName
24 | Provides the name which you want assigned to the application that is created by this script.
25 | .PARAMETER Company
26 | Provides the company name you want specified in all of the XML files.
27 | .PARAMETER AppRoot
28 | Provides the root directory for the application to be created. This should be pre-populated with the provided XML files,
29 | and it will be used as the source directory for all the deployment types.
30 | .PARAMETER Bitness
31 | Provides the desired architecture for the deployment types. All of the XML will be updated with this value.
32 | 'x86', 'x64'
33 | .PARAMETER VisioLicense
34 | Allows you to select the license type which you are licensed for. This will be either 'Online' or 'Volume'
35 | Note that if 'Volume' is selected, you will see that Visio 2016 as well as 2019 deployment types are created, and have requirements
36 | for Windows 7 or 8/8.1 attached to them. Visio 2019 deployment types are targeted at Windows 10.
37 | .PARAMETER ProjectLicense
38 | Allows you to select the license type which you are licensed for. This will be either 'Online' or 'Volume'
39 | Note that if 'Volume' is selected, you will see that Project 2016 as well as 2019 deployment types are created, and have requirements
40 | for Windows 7 or 8/8.1 attached to them. Project 2019 deployment types are targeted at Windows 10.
41 | .PARAMETER UpdateChannel
42 | Provides the desired Update Channel for the deployment types. All of the XML will be updated with this value.
43 | 'Semi-Annual', 'Semi-AnnualTargeted', 'Monthly', 'MonthlyTargeted'
44 | .PARAMETER AllowCdnFallback
45 | A boolean value that will be set in the XML files. This will allow your clients to fallback to the Content Delivery Network (CDN)
46 | aka 'the cloud.'
47 | .PARAMETER DisplayLevel
48 | Provides the desired display level for the Office 365 installer. This can be either 'Full' or 'None. All of the XML will be updated with this value.
49 |
50 | $appName = 'Office 365 - Visio Volume and Project Volume'
51 | $New365DynamicAppSplat = @{
52 | AppRoot = '\\contoso.com\DFS\CM\Applications\Office365\O365-DynamicInstall'
53 | ProjectLicense = 'Volume'
54 | ApplicationName = $AppName
55 | SMSProvider = 'SCCM'
56 | VisioLicense = 'Volume'
57 | Company = 'Contoso'
58 | Bitness = 'x64'
59 | UpdateChannel = 'Semi-Annual'
60 | }
61 | .\New-365DynamicApp.ps1 @New365DynamicAppSplat
62 |
63 | This will use the info and XML to generate an application with 17 deployment types for you. It is every combination of O365, Visio/Project Professional/Standard 2016/2019 volume licensed.
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CM-Rambings
2 | Place to put things that might make sense and have some use for CM admins.
3 |
--------------------------------------------------------------------------------
/RemoveExpiredUpdates.sql:
--------------------------------------------------------------------------------
1 | -- Delete expired updates that have beem marked as expired for more than @Days
2 | DECLARE @Days as int = 0
3 | exec spDeleteExpiredUpdates @Days
4 |
--------------------------------------------------------------------------------
/Repair-CMClientSettings:
--------------------------------------------------------------------------------
1 | <#
2 | Rebuilds all CM Client settings with a ' - Rebuild' note at the end.
3 | This simply loops all settings, recreates them, copies the agent configurations and redeploys them.
4 | NOTE: THIS DELETES THE OLD ONES!!!!!!!
5 | #>
6 | $all = Get-CMClientSetting
7 | foreach ($clientSetting in $all) {
8 | if ($clientSetting.Type -ne 0) {
9 | $newClientSetting = New-CMClientSetting -Name "$($clientSetting.Name) - Rebuild" -Type $clientSetting.Type
10 | $oldAgentConfigurations = $clientSetting.AgentConfigurations
11 | $oldDeployments = Get-CMClientSettingDeployment -InputObject $clientSetting
12 | $newClientSetting.SetArrayItems('AgentConfigurations', $oldAgentConfigurations)
13 | $newClientSetting.Put()
14 | foreach ($deployment in $oldDeployments) {
15 | New-CMClientSettingDeployment -InputObject $newClientSetting -CollectionId $deployment.CollectionID
16 | Remove-CMClientSettingDeployment -InputObject $deployment -Force
17 | }
18 | Remove-CMClientSetting -InputObject $clientSetting -Force
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Reprovision Windows 10 Apps/Get-DeprovisionedAppX.ps1:
--------------------------------------------------------------------------------
1 | function Get-DeprovisionedAppX {
2 | <#
3 | .SYNOPSIS
4 | Returns an array of apps that are deprovisioned
5 | .DESCRIPTION
6 | This function returns an array of all the apps that are deprovisioned on the local computer.
7 | Deprovisioned apps will show up in the registry if they were removed while Windows was offline, or
8 | with the PowerShell cmdlets for removing AppX Packages.
9 | .PARAMETER Filter
10 | Option filter that will be ran through as a '-match' so that regex can be used
11 | Accepts an array of strings, which can be a regex string if you wish
12 | .EXAMPLE
13 | PS C:\> Get-DeprovisionedAppX
14 | Return all deprovisioned apps on the local computers
15 | .EXAMPLE
16 | PS C:\> Get-DeprovisionedAppX -Filter Store
17 | Return all deprovisioned apps on the local computers that match the filter 'Store'
18 | #>
19 | param (
20 | [parameter(Mandatory = $false)]
21 | [string[]]$Filter
22 | )
23 | begin {
24 | $DeprovisionRoot = "registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\Deprovisioned"
25 | $AllDeprovisionedApps = Get-ChildItem -Path $DeprovisionRoot | Select-Object -Property @{ Name = 'DeprovisionedApp'; Expression = { $_.PSChildName } }
26 | if ($null -eq $AllDeprovisionedApps) {
27 | Write-Warning "There are no deprovisioned apps"
28 | }
29 | }
30 | process {
31 | switch ($PSBoundParameters.ContainsKey('Filter')) {
32 | $true {
33 | foreach ($SearchString in $Filter) {
34 | switch -regex ($AllDeprovisionedApps.DeprovisionedApp) {
35 | $SearchString {
36 | [PSCustomObject]@{
37 | 'DeprovisionedApp' = $PSItem
38 | }
39 | }
40 | default {
41 | Write-Verbose "$PSItem does not match the filter `'$SearchString`""
42 | }
43 | }
44 | }
45 | }
46 | $false {
47 | Write-Output $AllDeprovisionedApps
48 | }
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/Reprovision Windows 10 Apps/Inventory-DeprovisionedAppX.ps1:
--------------------------------------------------------------------------------
1 | #region define your Hardware Inventory Class Name, and the namespace in WMI to store it
2 | $HinvClassName = 'DeprovisionedAppX'
3 | $HinvNamespace = 'root\CustomHinv'
4 | #endregion define your Hardware Inventory Class Name, and the namespace in WMI to store it
5 |
6 | #region test if the namespace exists, and create it if it does not
7 | try {
8 | $null = [wmiclass]"$HinvNamespace`:__NameSpace"
9 | }
10 | catch {
11 | $HinvNamespaceSplit = $HinvNamespace -split '\\'
12 | $PathToTest = $HinvNamespaceSplit[0]
13 | for (${i} = 1; ${i} -lt $($HinvNamespaceSplit.Count); ${i}++) {
14 | $PathToTest = [string]::Join('\', @($PathToTest, $HinvNamespaceSplit[$i]))
15 | try {
16 | $null = [wmiclass]"$PathToTest`:__NameSpace"
17 | }
18 | catch {
19 | $PathToTestParent = Split-Path -Path $PathToTest -Parent
20 | $PathToTestName = Split-Path -Path $PathToTest -Leaf
21 | $NewNamespace = [wmiclass]"$PathToTestParent`:__NameSpace"
22 | $NamespaceCreation = $NewNamespace.CreateInstance()
23 | $NamespaceCreation.Name = $PathToTestName
24 | $null = $NamespaceCreation.Put()
25 | }
26 | }
27 | }
28 | #endregion test if the namespace exists, and create it if it does not
29 |
30 | #region clear our class from the namespace if it exists
31 | Remove-WmiObject -Class $HinvClassName -Namespace $HinvNamespace -ErrorAction SilentlyContinue
32 | #endregion clear our class from the namespace if it exists
33 |
34 | #region create the WMI class, and set the properties to be inventoried
35 | $HinvClass = [System.Management.ManagementClass]::new($HinvNamespace, [string]::Empty, $null)
36 | $HinvClass["__CLASS"] = $HinvClassName
37 | $HinvClass.Qualifiers.Add("Static", $true)
38 | $HinvClass.Properties.Add("DeprovisionedApp", [System.Management.CimType]::String, $false)
39 | $HinvClass.Properties["DeprovisionedApp"].Qualifiers.Add("Key", $true)
40 | $null = $HinvClass.Put()
41 | #endregion create the WMI class, and set the properties to be inventoried
42 |
43 | $DeprovisionRoot = "registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\Deprovisioned"
44 | $AllDeprovisionedApps = Get-ChildItem -Path $DeprovisionRoot | Select-Object -ExpandProperty PSChildName
45 | if ($null -ne $AllDeprovisionedApps) {
46 | foreach ($App in $AllDeprovisionedApps) {
47 | $null = Set-WmiInstance -Namespace $HinvNamespace -Class $HinvClassName -ErrorAction SilentlyContinue -Arguments @{
48 | DeprovisionedApp = $App
49 | }
50 | }
51 | }
52 |
53 | Write-Output 'Inventory Complete'
--------------------------------------------------------------------------------
/Reprovision Windows 10 Apps/Reprovision-AppX.ps1:
--------------------------------------------------------------------------------
1 | function Reprovision-AppX {
2 | <#
3 | .SYNOPSIS
4 | 'Reprovision' apps by removing the registry key that prevents app reinstall
5 | .DESCRIPTION
6 | Starting in Windows 10 1803, a registry key is set for every deprovisioned app. As long as this registry key
7 | is in place, a deprovisioned application will not be reinstalled during a feature update. By removing these
8 | registry keys, we can ensure that deprovisioned apps, such as the windows store are able to be reinstalled.
9 | .PARAMETER DeprovisionedApp
10 | The full name of the app to reprovision, as it appears in the registry. You can easily get this name using
11 | the Get-DeprovisionedApp function.
12 | .EXAMPLE
13 | PS C:\> Reprovision-AppX -DeprovisionedApp 'Microsoft.WindowsAlarms_8wekyb3d8bbwe'
14 | Removes the registry key for the deprovisioned WindowsAlarms app. The app will return after the next
15 | feature update.
16 | .INPUTS
17 | [string[]]
18 | .NOTES
19 | You must provide the exact name of the app as it appears in the registry. This is the full app 'name' - It is
20 | recommended to first use the Get-DeprovisionApp function to find apps that can be reprovisioned.
21 | #>
22 | [CmdletBinding(SupportsShouldProcess)]
23 | param(
24 | [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
25 | [string[]]$DeprovisionedApp
26 | )
27 | begin {
28 | $DeprovisionRoot = "registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\Deprovisioned"
29 | $AllDeprovisionedApps = Get-ChildItem -Path $DeprovisionRoot
30 | if ($null -eq $AllDeprovisionedApps) {
31 | Write-Warning "There are no deprovisioned apps"
32 | }
33 | }
34 | process {
35 | foreach ($App in $DeprovisionedApp) {
36 | $DeprovisionedAppPath = Join-Path -Path $DeprovisionRoot -ChildPath $App
37 | if ($PSCmdlet.ShouldProcess($App, "Reprovision-App")) {
38 | $AppPath = Resolve-Path -Path $DeprovisionedAppPath -ErrorAction Ignore
39 | if ($null -ne $AppPath) {
40 | Remove-Item -Path $AppPath.Path -Force
41 | }
42 | else {
43 | Write-Warning "App $App was not found to be deprovisioned"
44 | }
45 | }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/Script-InvokeBaseline.ps1:
--------------------------------------------------------------------------------
1 | param(
2 | [string]$BLName
3 | )
4 |
5 | $BLQuery = [string]::Format("SELECT * FROM SMS_DesiredConfiguration WHERE DisplayName = '{0}'", $BLName)
6 |
7 |
8 | $getBaselineSplat = @{
9 | Namespace = 'root\ccm\dcm'
10 | ErrorAction = 'Stop'
11 | Query = $BLQuery
12 | }
13 |
14 | $invokeBaselineEvalSplat = @{
15 | Namespace = 'root\ccm\dcm'
16 | ClassName = 'SMS_DesiredConfiguration'
17 | ErrorAction = 'Stop'
18 | Name = 'TriggerEvaluation'
19 | }
20 |
21 | $PropertyOptions = 'IsEnforced', 'IsMachineTarget', 'Name', 'PolicyType', 'Version'
22 |
23 | $BL = Get-CimInstance @getBaselineSplat
24 |
25 |
26 | $ArgumentList = @{ }
27 | foreach ($Property in $PropertyOptions) {
28 | $PropExist = Get-Member -InputObject $BL -MemberType Properties -Name $Property -ErrorAction SilentlyContinue
29 | switch ($PropExist) {
30 | $null {
31 | continue
32 | }
33 | default {
34 | $TypeString = ($PropExist.Definition.Split(' '))[0]
35 | $Type = [scriptblock]::Create("[$TypeString]")
36 | $ArgumentList[$Property] = $BL.$Property -as (. $Type)
37 | }
38 | }
39 | }
40 | $invokeBaselineEvalSplat['Arguments'] = $ArgumentList
41 |
42 | Invoke-CimMethod @invokeBaselineEvalSplat
--------------------------------------------------------------------------------
/Set-CMDistributionPointMaintenanceMode.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | Allows you to toggle maintenance mode on a distribution point
4 | .DESCRIPTION
5 | This function allows you to select a distribution point and set whether the 'Maintenance Mode' feature introduced in ConfigMgr 1902
6 | is toggled on or off.
7 | .PARAMETER SMSProvider
8 | Define the SMS Provider which the WMI queries will execute against.
9 | .PARAMETER DistributionPoint
10 | Provides the Distribution Point which you want to change the maintenance mode of. This should be provided as a FQDN,
11 | but if you provide the shortname we will also attempt a search with a wildcard.
12 | .PARAMETER MaintenanceMode
13 | The desired state of of Maintenance Mode for the distribution point. This is either 'On' or 'Off'
14 | .PARAMETER Force
15 | Bypass confirmation prompts.
16 | .EXAMPLE
17 | C:\PS> Set-CMDistributionPointMaintenanceMode -SMSProvider SCCM.CONTOSO.COM -DistributionPoint DP.CONTOSO.COM -MaintenanceMode On
18 | .NOTES
19 | FileName: Set-CMDistributionPointMaintenanceMode.ps1
20 | Author: Cody Mathis
21 | Contact: @CodyMathis123
22 | Created: 2019-06-11
23 | Updated: 2019-06-11
24 |
25 | The account you run this as must have the proper permissions to perform the maintenance mode action
26 | #>
27 | function Set-CMDistributionPointMaintenanceMode {
28 | [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
29 | param(
30 | [parameter(Mandatory = $true)]
31 | [string]$SMSProvider,
32 | [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
33 | [Alias('ComputerName', 'Name', 'NetworkOSPath')]
34 | [string]$DistributionPoint,
35 | [parameter(Mandatory = $true)]
36 | [ValidateSet('On', 'Off')]
37 | [string]$MaintenanceMode,
38 | [parameter(Mandatory = $false)]
39 | [switch]$Force
40 | )
41 | begin {
42 | $SiteCode = $(((Get-CimInstance -Namespace "root\sms" -ClassName "__Namespace" -ComputerName $SMSProvider).Name).substring(8 - 3))
43 | $Namespace = [string]::Format('root\sms\site_{0}', $SiteCode)
44 | $null = $PSBoundParameters.Remove('Force')
45 | $PSBoundParameters.Confirm = $false
46 | }
47 | process {
48 | foreach ($Computer in $DistributionPoint) {
49 | try {
50 | #We remove \ if we find them, such as when NetworkOSPath is pipe from Get-CMDistributionPoint
51 | $Computer = $Computer -replace "\\"
52 |
53 | #region Query SMS Provider for DP instance
54 | $Filter = [string]::Format("Name = '{0}'", $Computer)
55 | $getCimInstanceSplat = @{
56 | Filter = $Filter
57 | ComputerName = $SMSProvider
58 | Namespace = $Namespace
59 | ClassName = 'SMS_DistributionPointInfo'
60 | }
61 | $DP = Get-CimInstance @getCimInstanceSplat
62 | if ($null -eq $DP) {
63 | $Filter = [string]::Format("Name LIKE '{0}%'", $Computer)
64 | Write-Warning "Falling back to a wildcard filter [Filter = `"$Filter`"]"
65 | $getCimInstanceSplat['Filter'] = $Filter
66 | $DP = Get-WmiObject @getCimInstanceSplat
67 | if ($null -eq $DP) {
68 | Write-Error "WMI query for a distribution point succeded, but no object was returned. [Filter = `"$Filter`"] against [SMSProvider=$SMSProvider]" -ErrorAction Stop
69 | }
70 | }
71 | Write-Verbose "Identified Distribution point with [NALPath=$($DP.NALPath)]"
72 | #endregion Query SMS Provider for DP instance
73 | }
74 | catch {
75 | Write-Error "Failed to query for a distribution point with [Filter = `"$Filter`"] against [SMSProvider=$SMSProvider]" -ErrorAction Stop
76 | }
77 |
78 | #region convert from On or Off to a simple binary number to pass to the method
79 | $Mode = switch ($MaintenanceMode) {
80 | 'On' {
81 | 1
82 | }
83 | 'Off' {
84 | 0
85 | }
86 | }
87 | #endregion convert from On or Off to a simple binary number to pass to the method
88 |
89 | try {
90 | #region Invoke maintenance mode according to input parameters, note that Mode is cast as [uint32]
91 | $invokeCimMethodSplat = @{
92 | ClassName = 'SMS_DistributionPointInfo'
93 | ComputerName = $SMSProvider
94 | Namespace = $Namespace
95 | MethodName = 'SetDPMaintenanceMode'
96 | Arguments = @{
97 | NALPath = $DP.NALPath
98 | Mode = [uint32]$Mode
99 | }
100 | }
101 | if ($Force -or $PSCmdlet.ShouldProcess($Computer, "MaintenanceMode $MaintenanceMode")) {
102 | $Return = Invoke-CimMethod @invokeCimMethodSplat
103 | if ($Return.ReturnValue -ne 0) {
104 | Write-Error "Failed to set [DistributionPoint=$Computer] [MaintenanceMode=$MaintenanceMode] against [SMSProvider=$SMSProvider]" -ErrorAction Stop
105 | }
106 | elseif ($Return.ReturnValue -eq 0) {
107 | Write-Verbose "Set [DistributionPoint=$Computer] [MaintenanceMode=$MaintenanceMode]"
108 | }
109 | }
110 | #endregion Invoke maintenance mode according to input parameters, note that Mode is cast as [uint32]
111 | }
112 | catch {
113 | Write-Error "Failed to invoke maintenance mode change for [DistributionPoint=$Computer] [MaintenanceMode=$MaintenanceMode] against [SMSProvider=$SMSProvider]" -ErrorAction Stop
114 | }
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/Set-WSUSContentPath.ps1:
--------------------------------------------------------------------------------
1 | $Remediate = $false
2 |
3 | $PathShouldBeROOT = Get-ItemProperty -Path "registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Update Services\Server\Setup" -Name ContentDir | Select-Object -ExpandProperty ContentDir
4 | $PathShouldBe = Join-Path -Path $PathShouldBeROOT -ChildPath 'WSUSContent'
5 |
6 | [Void][Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
7 | $serverManager = New-Object Microsoft.Web.Administration.ServerManager
8 | $site = $serverManager.Sites | Where-Object { $_.Name -eq "WSUS Administration" }
9 | $rootApp = $site.Applications | Where-Object { $_.Path -eq "/" }
10 | $rootVdir = $rootApp.VirtualDirectories | Where-Object { $_.Path -eq "/Content" }
11 | $CurrentPath = $rootVdir.PhysicalPath
12 |
13 | switch ($CurrentPath -eq $PathShouldBe) {
14 | $true {
15 | $true
16 | }
17 | $false {
18 | switch ($Remediate) {
19 | $true {
20 | $rootVdir.PhysicalPath = $PathShouldBe
21 | $null = $serverManager.CommitChanges()
22 | $true
23 | }
24 | $false {
25 | $false
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Set-WSUSContentPoolAuth.ps1:
--------------------------------------------------------------------------------
1 | $Remediate = $false
2 | Import-Module WebAdministration
3 | $UseAppPoolIdentity = (Get-WebConfigurationProperty -Filter 'system.WebServer/security/authentication/AnonymousAuthentication' -Name username -Location 'WSUS Administration/Content') -eq ''
4 | switch ($UseAppPoolIdentity) {
5 | $true {
6 | $true
7 | }
8 | $false {
9 | switch ($Remediate) {
10 | $true {
11 | Set-WebConfigurationProperty -Filter 'system.WebServer/security/authentication/AnonymousAuthentication' -name username -value '' -location 'WSUS Administration/Content'
12 | $true
13 | }
14 | $false {
15 | $false
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Start-IISLogCleanup.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | IIS Log Cleanup
4 | .DESCRIPTION
5 | This script will cleanup all IIS logs according to the LogCleanupDays parameter, and the Remediate parameter.
6 | This was written for use in a MEMCM Configuration Item. You can paste this script into both detection, and
7 | remediation, adjusting the $Remediate paramater appropraitely. Ensure that the $LogCleanupDays parameter
8 | matches in both scripts.
9 | .PARAMETER Remediate
10 | A boolean that determines if the logs will be cleaned up, or if we simply return compliance
11 | .PARAMETER LogCleanupDays
12 | A positive integer value of days which you want to retain logs for, defaulting to 7. Anything older than the
13 | specified number of days will be removed, or used to return compliance if remediation is set to false.
14 | .EXAMPLE
15 | C:\PS> Start-IISLogCleanup -Remediate $False -LogCleanupDays 7
16 | Return a boolean based on whether there are log files older than 7 days
17 | .EXAMPLE
18 | C:\PS> Start-IISLogCleanup -Remediate $False -LogCleanupDays 7
19 | Remove files older than 7 days, and return a boolean of $true if it was succesful
20 | .OUTPUTS
21 | [bool]
22 | .NOTES
23 | This is just the function declaration. You should call the function, as you see at the end of the file
24 | based on the part of your CI this script is in. You would call it with -Remediate $false for detection
25 | and then call it with -Remediate $true for remediation.
26 |
27 | FileName: Start-IISLogCleanup.ps1
28 | Author: Cody Mathis
29 | Contact: @CodyMathis123
30 | Contributor: Vex
31 | Created: 2020-04-09
32 | Version: 1.0.2
33 | Updated:
34 | Version 1.0.0 2020-04-09 - Initial Release
35 | Version 1.0.1 2020-04-09 - Cleaned up
36 | Version 1.0.2 2020-04-09 - Added detection for available module; added function
37 |
38 | #>
39 | Function Start-IISLogCleanup {
40 | param(
41 | [Parameter(Mandatory = $false)]
42 | [bool]$Remediate = $false,
43 | [Parameter(Mandatory = $false)]
44 | [ValidateRange(1, [int]::MaxValue)]
45 | [int]$LogCleanupDays = 7
46 | )
47 |
48 | If (Get-Module -ListAvailable | Where-Object { $_.Name -eq 'WebAdministration' } ) {
49 | Import-Module WebAdministration
50 | }
51 | Else {
52 | Write-Verbose "No WebAdministration. Compliant."
53 | return $true
54 | }
55 |
56 | $AllWebsites = Get-Website
57 |
58 | #region Loop through all websites, identify log file path, and check for old files. Removing according to remediation preference
59 | foreach ($WebSite in $AllWebsites) {
60 | $LogFilePath = [string]::Format("{0}\w3svc{1}", $WebSite.LogFile.Directory, $WebSite.ID).Replace('%SystemDrive%', $env:SystemDrive)
61 | if (Test-Path -Path $LogFilePath) {
62 | $AllLogFiles = Get-ChildItem -Path $LogFilePath -Filter "*.log" -Recurse
63 | if ($OldLogs = $AllLogFiles.Where( { $_.LastWriteTime -lt (Get-Date).AddDays(-$LogCleanupDays) })) {
64 | switch ($Remediate) {
65 | $true {
66 | try {
67 | $OldLogs | Remove-Item -Force -ErrorAction Stop
68 | }
69 | catch {
70 | return $false
71 | }
72 | }
73 | $false {
74 | return $false
75 | }
76 | }
77 | }
78 | }
79 | }
80 | #endregion Loop through all websites, identify log file path, and check for old files. Removing according to remediation preference
81 |
82 | #region If we make it through the loop with no $false returns, then we are compliant. Return $True
83 | Write-Verbose "Compliant."
84 | return $true
85 | #endregion If we make it through the loop with no $false returns, then we are compliant. Return $True
86 | }
87 |
88 | Start-IISLogCleanup -Remediate $false -LogCleanupDays 30
89 |
--------------------------------------------------------------------------------
/prompt.ps1:
--------------------------------------------------------------------------------
1 | function global:Prompt {
2 | $Success = $?
3 |
4 | ## Time calculation
5 | $LastExecutionTimeSpan = if (@(Get-History).Count -gt 0) {
6 | Get-History | Select-Object -Last 1 | ForEach-Object {
7 | New-TimeSpan -Start $_.StartExecutionTime -End $_.EndExecutionTime
8 | }
9 | }
10 | else {
11 | New-TimeSpan
12 | }
13 |
14 | $LastExecutionShortTime = if ($LastExecutionTimeSpan.Days -gt 0) {
15 | "$($LastExecutionTimeSpan.Days + [Math]::Round($LastExecutionTimeSpan.Hours / 24, 2)) d"
16 | }
17 | elseif ($LastExecutionTimeSpan.Hours -gt 0) {
18 | "$($LastExecutionTimeSpan.Hours + [Math]::Round($LastExecutionTimeSpan.Minutes / 60, 2)) h"
19 | }
20 | elseif ($LastExecutionTimeSpan.Minutes -gt 0) {
21 | "$($LastExecutionTimeSpan.Minutes + [Math]::Round($LastExecutionTimeSpan.Seconds / 60, 2)) m"
22 | }
23 | elseif ($LastExecutionTimeSpan.Seconds -gt 0) {
24 | "$($LastExecutionTimeSpan.Seconds + [Math]::Round($LastExecutionTimeSpan.Milliseconds / 1000, 2)) s"
25 | }
26 | elseif ($LastExecutionTimeSpan.Milliseconds -gt 0) {
27 | "$([Math]::Round($LastExecutionTimeSpan.TotalMilliseconds, 2)) ms"
28 | }
29 | else {
30 | "0 s"
31 | }
32 |
33 | if ($Success) {
34 | Write-Host -Object "[$LastExecutionShortTime] " -NoNewline -BackgroundColor DarkGreen -ForegroundColor White
35 | }
36 | else {
37 | Write-Host -Object "! [$LastExecutionShortTime] " -NoNewline -BackgroundColor Red -ForegroundColor White
38 | }
39 |
40 | ## History ID
41 | $HistoryId = $MyInvocation.HistoryId - 1
42 | # Uncomment below for leading zeros
43 | # $HistoryId = '{0:d4}' -f $MyInvocation.HistoryId
44 | Write-Host -Object "$HistoryId`: " -NoNewline -BackgroundColor DarkCyan -ForegroundColor White
45 |
46 | ## User
47 | $IsAdmin = (New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
48 | Write-Host -Object "$($env:USERNAME) ($(if ($IsAdmin){ 'A' } else { 'U' })) " -NoNewline -BackgroundColor Red -ForegroundColor White
49 |
50 | ## Path FF
51 | $Drive = $pwd.Drive.Name
52 | $Pwds = $pwd -split "\\" | Where-Object { -Not [String]::IsNullOrEmpty($_) }
53 | $PwdPath = if ($Pwds.Count -gt 3) {
54 | $ParentFolder = Split-Path -Path (Split-Path -Path $pwd -Parent) -Leaf
55 | $CurrentFolder = Split-Path -Path $pwd -Leaf
56 | "..\$ParentFolder\$CurrentFolder"
57 | }
58 | elseif ($Pwds.Count -eq 3) {
59 | $ParentFolder = Split-Path -Path (Split-Path -Path $pwd -Parent) -Leaf
60 | $CurrentFolder = Split-Path -Path $pwd -Leaf
61 | "$ParentFolder\$CurrentFolder"
62 | }
63 | elseif ($Pwds.Count -eq 2) {
64 | Split-Path -Path $pwd -Leaf
65 | }
66 | else {
67 | ""
68 | }
69 |
70 | Write-Host -Object "$Drive`:\$PwdPath" -NoNewline -BackgroundColor Magenta -ForegroundColor White
71 |
72 | return ">`n"
73 | }
--------------------------------------------------------------------------------