├── AD_DHCP_UEFI_SCOPE_OPTIONS.ps1 ├── ContosoLogo350x105.png ├── Deploy-AppToCollection.ps1 ├── Export-CmInventory.ps1 ├── Export-CmReports.ps1 ├── Get-CMSQLQueryData.ps1 ├── Get-CmAppInstalls.ps1 ├── Get-SqlExpressInstalls.ps1 ├── Install-PSModule.ps1 ├── Invoke-PhasedUpgrade.ps1 ├── OSD ├── Copy-BootImageDrivers.ps1 ├── Export-CmTaskSequences.ps1 ├── Get-ComputerAdSite.ps1 ├── Get-NextADDeviceName.ps1 ├── Get-NextCMDeviceName.ps1 ├── Grant-MdtSharePermissions.ps1 ├── ImportDrivers.ps1 ├── Invoke-HpBiosConfig.ps1 ├── LocMapping.csv ├── Move-ComputerOU.ps1 ├── OuMapping.xml ├── README.md ├── Send-TSNotifications.md ├── Set-ComputerNameIncrementAD.ps1 ├── Set-ComputerNameIncrementCM.ps1 ├── Set-ComputerNameX.ps1 ├── Set-ComputerOUPath.ps1 ├── Set-OSDComputerName.ps1 ├── Set-OSDComputerName1.ps1 ├── Set-OSDComputerName2.ps1 ├── Set-OSDComputerName3.ps1 ├── Set-OSDComputerName4.ps1 ├── Set-OSDComputerName5.ps1 ├── Set-OSDComputerName6.ps1 ├── Set-OSDComputerName7.ps1 ├── Set-OSDDeviceMapping.ps1 ├── Show-FormDialog.ps1 ├── Show-TsVars.ps1 ├── TaskSequenceGoodies.md ├── Test-CMDeviceNameADConflict.ps1 ├── Test-NetworkConnectionType.ps1 ├── desktops-ous.txt ├── laptops-ous.txt ├── locations.txt ├── osd-locations.csv ├── oulocations.txt └── ps-delay-120sec.cmd ├── README.md ├── Run-CmCustomQuery.ps1 ├── UD └── New-CMWebService.ps1 ├── WQL ├── clients_by_ou.wql └── clients_laptops.wql ├── _CM_TEMPLATE.ps1 ├── cmtools ├── Clear-ScomAgentCache.ps1 └── Get-CmDbInfo.ps1 ├── collections ├── Add-CMDeviceToCollection.ps1 ├── Compare-ListToCmCollection.ps1 ├── Export-CmCollectionMembers.ps1 ├── Get-CMCollectionID.ps1 ├── Get-CMCollectionMember.ps1 ├── Get-CMCollectionMemberFileMember.ps1 ├── Get-CMCollectionsList.ps1 ├── Get-CMDeviceCollections.ps1 ├── Get-CmObjectCollection.ps1 ├── Get-ICmCollectionMembers.ps1 ├── Import-CMCollectionMembersFromFile.ps1 ├── Import-CMCustomCollections.ps1 ├── Select-CmCollectionFromList.ps1 └── customcollections.json ├── config.json ├── crap └── Get-CMAdoConnection.ps1 ├── demo ├── Create-DslShare.ps1 ├── Download-AppSources.ps1 ├── Export-SqlAuditReport.ps1 ├── Get-CmQueryData.ps1 ├── Get-NetworkInfo.ps1 ├── cb_chocolatey.ps1 ├── ci_chocolatey.ps1 ├── downloads.txt └── folders.txt ├── devices ├── Collect-ClientLogFiles.ps1 ├── Collect-SystemEventLogs.ps1 ├── Get-CMDeviceInfo.ps1 ├── Get-CmDeviceSummary.ps1 ├── Get-NextAdComputerName.ps1 ├── Get-OSComputerOU.ps1 ├── Invoke-CmClientAction.ps1 ├── Remove-AdCmComputer.ps1 ├── Remove-CmClient.ps1 ├── Set-CmClientSiteCode.ps1 └── Windows10SysPrepDebloater.ps1 ├── queries ├── AppInstalls-Top100.sql ├── Clients-BiosVersions.sql ├── Clients-Dell-D6000-Docks.sql ├── Clients-DockModels.sql ├── Clients-IPGateways.sql ├── Clients-Inventory-All.sql ├── Clients-Inventory-General.sql ├── Clients-Inventory-Models.sql ├── Clients-Inventory-OsVersions.sql ├── Clients-OldHwInventory.sql ├── Clients-Summary.sql ├── Clients-TPMStatus.sql ├── Clients-TopUsers.sql ├── Clients-TotalMemory.sql ├── Clients-WuVersions.sql ├── Computers-ADSites.sql ├── Run-Query.ps1 ├── Site-DPServers.sql ├── Site-DPStatus.sql ├── Software-Deployments-Summary.sql ├── Software-Google-BackupSync.sql ├── Software-Google-Chrome.sql ├── Software-OfficeProducts-AllVersions.sql ├── Software-OfficeProducts-Detailed.sql ├── Software-OfficeProducts-Detailed2.sql ├── Software-OfficeProducts-PlatformVersion.sql ├── Software-OfficeProducts-Project.sql ├── Software-OfficeProducts-Summary.sql ├── Software-OfficeProducts-VersionCounts.sql ├── Software-OfficeProducts-Versions.sql ├── Software-OfficeProducts-Visio.sql ├── Software-OneDrive-Detailed.sql ├── Software-OneDrive-Totals.sql ├── Software-SQLExpress-Counts.sql ├── Software-Symantec-NoDiskEncryption.sql ├── Users-Machine-Logins.sql ├── Users.sql └── queries.txt └── site ├── Disable-IPv6.ps1 ├── Export-CmHwInventoryClasses.ps1 ├── Get-CmFullVersionName.ps1 ├── Get-CmHwInvClasses.ps1 ├── Get-CmMaintenanceTasksInfo.ps1 ├── Get-CmPsModulePath.ps1 ├── Get-CmSiteCode.ps1 ├── Get-CmSiteDBInstance.ps1 ├── Get-CmSiteInfo.ps1 ├── Get-CmSiteInstallPath.ps1 ├── Get-CmSiteVersion.ps1 ├── Get-CmSqlInfo.ps1 ├── Get-WebServersWithSSL.ps1 ├── Import-CMModule.ps1 ├── Import-CmSiteBoundaries.ps1 ├── Send-CmSiteServerLogs.ps1 ├── Set-CmLab-WsusDBFilePaths.ps1 ├── Set-CmLab-WsusPoolOptions.ps1 ├── Set-DhcpUefiOptions.ps1 ├── Set-MdtSharePermissions.ps1 ├── Test-CmPorts.ps1 ├── Update-CmAppSourcePaths.ps1 ├── Update-CmPackageSourcePaths.ps1 ├── cm-site-status.xml ├── sqlserverversions.csv ├── sqlversions.csv └── sqlversions.csv.xlsx /AD_DHCP_UEFI_SCOPE_OPTIONS.ps1: -------------------------------------------------------------------------------- 1 | $DhcpHost = 'DC1' 2 | $DhcpFQDN = 'DC1.contoso.com' 3 | # address of DHCP host 4 | $ScopeID = '192.168.29.10' 5 | # address of PXE host 6 | $Option66 = '192.168.29.30' 7 | 8 | # Set Vendor Classes: 9 | 10 | Add-DhcpServerv4Class -Name "PXEClient (UEFI x64)" ` 11 | -Description "PXE:Arch:00007" ` 12 | -Type Vendor -Data "PXE:Arch:00007" ` 13 | -Computer $DhcpHost 14 | 15 | Add-DhcpServerv4Class -Name "PXEClient (UEFI x86)" ` 16 | -Description "PXE:Arch:00006" ` 17 | -Type Vendor -Data "PXE:Arch:00006" ` 18 | -Computer $DhcpHost 19 | 20 | Add-DhcpServerv4Class -Name "PXEClient (BIOS x86 & x64)" ` 21 | -Description "PXE:Arch:00000" ` 22 | -Type Vendor -Data "PXE:Arch:00000" ` 23 | -Computer $DhcpHost 24 | 25 | # Create DHCP Policies (Leaving out the "ScopeId" option will make the policy a server level policy): 26 | 27 | Add-DhcpServerv4Policy -Name "PXEClient (UEFI x64)" ` 28 | -Description "Set correct server and file name for UEFI x64 PXE" ` 29 | -Condition OR ` 30 | -VendorClass EQ, "PXEClient (UEFI x64)*" ` 31 | -ComputerName $DhcpFQDN ` 32 | -ScopeId $ScopeID 33 | 34 | Add-DhcpServerv4Policy -Name "PXEClient (UEFI x86)" ` 35 | -Description "Set correct server and file name for UEFI x86 PXE" ` 36 | -Condition OR ` 37 | -VendorClass EQ, "PXEClient (UEFI x86)*" ` 38 | -ComputerName $DhcpFQDN ` 39 | -ScopeId $ScopeID 40 | 41 | Add-DhcpServerv4Policy -Name "PXEClient (BIOS x86 & x64)" ` 42 | -Description "Set correct server and file name for BIOS x86 & x64 PXE" ` 43 | -Condition OR ` 44 | -VendorClass EQ, "PXEClient (BIOS x86 & x64)*" ` 45 | -ComputerName $DhcpFQDN ` 46 | -ScopeId $ScopeID 47 | 48 | # Set Policy Options (If server level policy, do not specify the "ScopeId" option): 49 | 50 | # ....For UEFI x64 51 | 52 | Set-DhcpServerv4OptionValue -ComputerName $DhcpHost ` 53 | -ScopeId $ScopeID ` 54 | -PolicyName "PXEClient (UEFI x64)" ` 55 | -OptionId 60 ` 56 | -Value PXEClient 57 | 58 | Set-DhcpServerv4OptionValue -ComputerName $DhcpHost ` 59 | -ScopeId $ScopeID ` 60 | -PolicyName "PXEClient (UEFI x64)" ` 61 | -OptionId 66 ` 62 | -Value $Option66 63 | 64 | Set-DhcpServerv4OptionValue -ComputerName $DhcpHost ` 65 | -ScopeId $ScopeID ` 66 | -PolicyName "PXEClient (UEFI x64)" ` 67 | -OptionId 67 ` 68 | -Value "smsboot\x64\wdsmgfw.efi" 69 | 70 | # ....For UEFI x86 71 | 72 | Set-DhcpServerv4OptionValue -ComputerName $DhcpHost ` 73 | -ScopeId $ScopeID ` 74 | -PolicyName "PXEClient (UEFI x86)" ` 75 | -OptionId 60 -Value PXEClient 76 | 77 | Set-DhcpServerv4OptionValue -ComputerName $DhcpHost ` 78 | -ScopeId $ScopeID ` 79 | -PolicyName "PXEClient (UEFI x86)" ` 80 | -OptionId 66 -Value $Option66 81 | 82 | Set-DhcpServerv4OptionValue -ComputerName $DhcpHost ` 83 | -ScopeId $ScopeID ` 84 | -PolicyName "PXEClient (UEFI x86)" ` 85 | -OptionId 67 ` 86 | -Value "smsboot\x86\wdsmgfw.efi" 87 | 88 | # ....For BIOS x86 & x64 89 | 90 | Set-DhcpServerv4OptionValue -ComputerName $DhcpHost ` 91 | -ScopeId $ScopeID ` 92 | -PolicyName "PXEClient (BIOS x86 & x64)" ` 93 | -OptionId 66 ` 94 | -Value $Option66 95 | 96 | Set-DhcpServerv4OptionValue -ComputerName $DhcpHost ` 97 | -ScopeId $ScopeID ` 98 | -PolicyName "PXEClient (BIOS x86 & x64)" ` 99 | -OptionId 67 ` 100 | -Value "smsboot\x64\wdsnbp.com" 101 | -------------------------------------------------------------------------------- /ContosoLogo350x105.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skatterbrainz/sccm/011611aeaa75e67817c6bd671906bb1f0c79a6e5/ContosoLogo350x105.png -------------------------------------------------------------------------------- /Deploy-AppToCollection.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [parameter(Mandatory=$True)] [string] $DeviceName = "Win10A", 3 | [parameter(Mandatory=$True)] [string] $AppName = "7-zip", 4 | [parameter(Mandatory=$True)] [string] $CollectionName = "Test Workstations" 5 | ) 6 | 7 | 8 | New-CmDeviceCollection -Name $CollectionName -LimitingCOllectionName "All Systems" -RefreshType ConstantUpdate 9 | 10 | $Resource = Get-CmDevice -Name $DeviceName 11 | 12 | Add-CmDeviceCollectionDirectMembershipRule -CollectionName $CollectionName -ResourceID $Resource.ResourceID 13 | 14 | Start-CmApplicationDeploymentSimulation -CollectionName $CollectionName -Name $AppName -DeployAction Install 15 | 16 | -------------------------------------------------------------------------------- /Export-CmInventory.ps1: -------------------------------------------------------------------------------- 1 | #requires -modules dbatools,importexcel 2 | 3 | <# 4 | .SYNOPSIS 5 | Dump inventory data from ConfigMgr site database 6 | .DESCRIPTION 7 | Dump inventory summary data from ConfigMgr SQL database into Excel spreadsheet 8 | .PARAMETER SiteCode 9 | Configuration Manager site code 10 | .PARAMETER DbHost 11 | SQL Server instance hostname (default is "localhost") 12 | .PARAMETER DbName 13 | SQL Server Database name (default is "CM_$SiteCode") 14 | .PARAMETER ReportPath 15 | Path to output report files 16 | .PARAMETER ConfigFile 17 | Path to SQL query configurations JSON file (default is .\config.json) 18 | .PARAMETER Excel 19 | Export to Excel XLSX file, otherwise output to CSV files (one for each query) 20 | .EXAMPLE 21 | .\Export-CmInventory.ps1 -SiteCode "P01" 22 | Export from P01 site database on localhost to Excel xlsx file 23 | .EXAMPLE 24 | .\Export-CmInventory.ps1 -SiteCode "P01" -DbHost "server2" -DbName "SCCM_P01" 25 | Export from P01 site database "SCCM_PO1" hosted on server2 to Excel xlsx file 26 | .NOTES 27 | 1.0.0 - 1910.30 - David Stein - First release 28 | Requires config.json from this same repo location 29 | #> 30 | [CmdletBinding()] 31 | param( 32 | [parameter(Mandatory)][ValidateLength(3,3)][string] $SiteCode, 33 | [parameter()][ValidateNotNullOrEmpty()][string] $DbHost = "localhost", 34 | [parameter()][ValidateNotNullOrEmpty()][string] $DbName = "CM_$SiteCode", 35 | [parameter()][ValidateNotNullOrEmpty()][string] $ReportPath = "$env:USERPROFILE\documents", 36 | [parameter()][ValidateNotNullOrEmpty()][string] $ConfigFile = ".\config.json", 37 | [parameter()][bool] $Excel = $True 38 | ) 39 | $ErrorActionPreference = 'stop' 40 | $XlFile = $(Join-Path $ReportPath "$SiteCode`_Inventory.xlsx") 41 | 42 | if (Test-Path $XlFile) { Remove-Item -Path $XlFile -Force } 43 | 44 | function Invoke-DataExport { 45 | [CmdletBinding()] 46 | param ( 47 | [parameter(Position=0)][ValidateNotNullOrEmpty()][string] $Query, 48 | [parameter(Position=1)][ValidateNotNullOrEmpty()][string] $ReportName, 49 | [parameter()][string[]] $Properties 50 | ) 51 | try { 52 | Write-Host "exporting: $ReportName" -ForegroundColor Cyan 53 | if ($Excel -eq $True) { 54 | Invoke-DbaQuery -SqlInstance $DbHost -Database $DbName -Query $Query | 55 | Select-Object $Properties | 56 | Export-Excel -Path $XlFile -WorksheetName $ReportName 57 | } 58 | else { 59 | Invoke-DbaQuery -SqlInstance $DbHost -Database $DbName -Query $Query | 60 | Select-Object $Properties | 61 | Export-Csv -Path $(Join-Path $ReportPath "$SiteCode`_$ReportName.csv") -NoTypeInformation -Force 62 | } 63 | } 64 | catch { 65 | Write-Error $_.Exception.Message 66 | } 67 | } 68 | 69 | if (-not(Test-Path $ConfigFile)) { 70 | Write-Warning "configuration file not found: $ConfigFile" 71 | break 72 | } 73 | 74 | try { 75 | $cfg = Get-Content $ConfigFile | ConvertFrom-Json 76 | $keys = ($cfg.psobject.Properties).Name 77 | 78 | foreach ($key in $keys) { 79 | $qset = $cfg."$key" 80 | $qtext = $qset.query 81 | $props = $qset.properties -split ',' 82 | Invoke-DataExport -Query $qtext -ReportName $key -Properties $props 83 | } 84 | Write-Host "processing complete" -ForegroundColor Green 85 | } 86 | catch { 87 | Write-Error $_.Exception.Message 88 | } -------------------------------------------------------------------------------- /Export-CmReports.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Export-CmReports exports SCCM SQL RSP reports to RDL files in 4 | a specified location 5 | 6 | .PARAMETER SiteCode 7 | 3-character site code 8 | 9 | .PARAMETER HostName 10 | NetBios hostname of SCCM RSP host 11 | 12 | .PARAMETER ReportFolder 13 | Name of logical SSRS report folder, or "ALL" to export all folders 14 | Default is "/" which is not recursive 15 | 16 | .PARAMETER OutputFolder 17 | Path location where RDL files will be exported 18 | Default is $USERPROFILE\Documents 19 | 20 | .NOTES 21 | Written by: David Stein 22 | Date Create: 10/19/2016 23 | 24 | .EXAMPLE 25 | Export-CmReports -SiteCode "ABC" -HostName "CM1" 26 | Export-CmReports -SiteCode "ABC" -HostName "CM1" -ReportFolder "My Custom Reports" -OutputFolder "C:\Temp" 27 | Export-CmReports -SiteCode "ABC" -HostName "CM1" -ReportFolder "ALL" -OutputFolder "C:\Temp" 28 | #> 29 | 30 | 31 | function Export-CmReports { 32 | param ( 33 | [parameter(Mandatory=$True)] [string] $SiteCode, 34 | [parameter(Mandatory=$True)] [string] $HostName, 35 | [parameter(Mandatory=$False)] [string] $ReportFolder = "/", 36 | [parameter(Mandatory=$False)] [string] $OutputFolder = "$($env:USERPROFILE)\Documents" 37 | ) 38 | $url = "http://$HostName/ReportServer/ReportService2010.asmx?WSDL" 39 | Write-Host "connecting to SSRS web service..." -ForegroundColor Cyan 40 | $ssrs = New-WebServiceProxy -Uri $url -UseDefaultCredential -Namespace "ReportingWebService" 41 | if ($ReportFolder -eq "ALL") { 42 | $folders = $ssrs.ListChildren("/ConfigMgr_$SiteCode", $False) | ?{$_.TypeName -eq 'Folder'} 43 | } 44 | else { 45 | $folders = $ssrs.ListChildren("/ConfigMgr_$SiteCode", $False) | ?{$_.Name -eq "$ReportFolder"} 46 | } 47 | 48 | if ($folders.Length -gt 0) { 49 | foreach ($folder in $folders) { 50 | $fname = $folder.Name 51 | $fpath = $folder.Path 52 | $reports = $ssrs.ListChildren("$fPath" , $False) 53 | 54 | if ($reports.Length -gt 0) { 55 | 56 | Write-Host "Folder: $fName : $($reports.Length) reports" -ForegroundColor Cyan 57 | 58 | $OutPath = "$OutputFolder\$fName" 59 | 60 | if (!(Test-Path $OutPath)) { 61 | md $OutPath -Force 62 | } 63 | foreach ($r in $reports) { 64 | $reportName = $r.Name 65 | if ($r.Hidden -eq $True) { 66 | Write-Host "skipping hidden report: $reportName" -ForegroundColor Gray 67 | } 68 | else { 69 | Write-Host "reading: $reportName..." -ForegroundColor Green 70 | $def = $ssrs.GetItemDefinition($r.Path) 71 | $stream = [System.IO.File]::OpenWrite("$OutPath\$reportName.rdl") 72 | $stream.Write($def, 0, $def.Length) 73 | $stream.Close() 74 | Write-Host "exported: $reportName successfully!" -ForegroundColor Green 75 | } 76 | } 77 | } 78 | else { 79 | Write-Host "no reports were found" -ForegroundColor Cyan 80 | } 81 | } # foreach 82 | } 83 | Write-Host "done!" 84 | } 85 | -------------------------------------------------------------------------------- /Get-CMSQLQueryData.ps1: -------------------------------------------------------------------------------- 1 | function Get-CmSqlQueryData { 2 | [CmdletBinding()] 3 | param ( 4 | [parameter(Mandatory=$False, ValueFromPipeline=$True, HelpMessage="SQL Query Statement")] 5 | [ValidateNotNullOrEmpty()] 6 | [string] $Query, 7 | [parameter(Mandatory=$False, HelpMessage="SQL Server ADO Connection Object")] 8 | $AdoConnection 9 | ) 10 | Write-Verbose "----------------------------------------------" 11 | Write-Verbose "(Get-CMSqlQueryData)" 12 | $cmd = New-Object System.Data.SqlClient.SqlCommand($Query,$AdoConnection) 13 | $cmd.CommandTimeout = $QueryTimeout 14 | $ds = New-Object System.Data.DataSet 15 | $da = New-Object System.Data.SqlClient.SqlDataAdapter($cmd) 16 | [void]$da.Fill($ds) 17 | $rows = $($ds.Tables).Rows.Count 18 | Write-Verbose "$rows rows returned from query" 19 | Write-Output $($ds.Tables).Rows 20 | } 21 | -------------------------------------------------------------------------------- /Get-CmAppInstalls.ps1: -------------------------------------------------------------------------------- 1 | #requires -modules dbatools 2 | <# 3 | .DESCRIPTION 4 | Query ConfigMgr SQL database for software product installs 5 | .PARAMETER ProductName 6 | List: Office, ProjectStd, ProjectPro, VisioStd, VisioPro, All, Custom 7 | .PARAMETER AppFilter 8 | Product Name filter when using ProductName = Custom. Use % for wildcards 9 | .PARAMETER ServerName 10 | ConfigMgr SQL Server host name 11 | .PARAMETER SiteCode 12 | ConfigMGr site code 13 | .PARAMETER TotalCount 14 | Show total row counts only (default is show all rows) 15 | .PARAMETER Detailed 16 | Show additional columns in output 17 | .PARAMETER NoCount 18 | Do not show total row count when displaying row-level results (does not apply to -TotalCount) 19 | .EXAMPLE 20 | .\Get-CmAppInstalls.ps1 -ProductName ProjectPro 21 | .EXAMPLE 22 | .\Get-CmAppInstalls.ps1 -ProductName ProjectPro -Detailed 23 | .EXAMPLE 24 | .\Get-CmAppInstalls.ps1 -ProductName ProjectPro -TotalCount 25 | .EXAMPLE 26 | .\Get-CmAppInstalls.ps1 -ProductName Custom -AppFilter "Microsoft Project Standard 2013%" -Detailed 27 | .EXAMPLE 28 | .\Get-CmAppInstalls.ps1 -AppFilter "Microsoft Project%" -ServerName "cm01.contoso.local" -SiteCode "P01" 29 | .EXAMPLE 30 | .\Get-CmAppInstalls.ps1 -ProductName ProjectPro -NoCount) | Where {$_.Computer -like 'ABC123*'} 31 | .EXAMPLE 32 | .\Get-CmAppInstalls.ps1 -ProductName ProjectPro -NoCount) | Out-GridView 33 | .NOTES 34 | 2018.10.03 - DS - First release 35 | 2018.10.04 - DS - Added ProductName list, NoCount and Detailed params 36 | #> 37 | 38 | [CmdletBinding()] 39 | param ( 40 | [parameter(Mandatory=$False, HelpMessage="ConfigMgr Site Code")] 41 | [ValidateNotNullOrEmpty()] 42 | [string] $SiteCode = "P01", 43 | [parameter(Mandatory=$False, HelpMessage="ConfigMgr DB Server Name")] 44 | [ValidateNotNullOrEmpty()] 45 | [string] $ServerName = "localhost", 46 | [parameter(Mandatory=$False, HelpMessage="Product Name Filter")] 47 | [ValidateSet('Office','ProjectStd','ProjectPro','VisioStd','VisioPro','All','Custom')] 48 | [string] $ProductName = 'Office', 49 | [parameter(Mandatory=$False, HelpMessage="Product Name to filter on")] 50 | [ValidateNotNullOrEmpty()] 51 | [string] $AppFilter = "Microsoft Office 365 ProPlus%" 52 | ) 53 | 54 | switch ($ProductName) { 55 | 'Office' { 56 | $AppFilter = "Microsoft Office 365 ProPlus%" 57 | break 58 | } 59 | 'ProjectPro' { 60 | $AppFilter = "Microsoft Project Professional%" 61 | break 62 | } 63 | 'ProjectStd' { 64 | $AppFilter = "Microsoft Project Standard%" 65 | break 66 | } 67 | 'VisioPro' { 68 | $AppFilter = "Microsoft Visio Professional%" 69 | break 70 | } 71 | 'VisioStd' { 72 | $AppFilter = "Microsoft Visio Standard%" 73 | break 74 | } 75 | default { 76 | break 77 | } 78 | } 79 | 80 | $DatabaseName = "CM_$SiteCode" 81 | 82 | $columns = @" 83 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 AS ProductName, 84 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductVersion0 AS [Version], 85 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.Publisher0 AS Publisher 86 | "@ 87 | 88 | $groupby = @" 89 | GROUP BY ProductName0, ProductVersion0, Publisher0 90 | "@ 91 | 92 | if ($Detailed) { 93 | $columns += @" 94 | ,dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.InstallSource0 AS [Source], 95 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.InstalledLocation0 AS [Location] 96 | "@ 97 | $groupby += ",InstallSource0,InstalledLocation0" 98 | } 99 | 100 | if ($Product -eq 'ALL') { 101 | $query = @" 102 | SELECT DISTINCT 103 | $columns, COUNT(*) AS Installs 104 | FROM dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED 105 | $groupby 106 | "@ 107 | } 108 | else { 109 | $query = @" 110 | SELECT DISTINCT 111 | dbo.v_R_System.Name0 AS Computer, $columns 112 | FROM dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED INNER JOIN 113 | dbo.v_R_System ON dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ResourceID = dbo.v_R_System.ResourceID 114 | WHERE (dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 LIKE '$AppFilter') 115 | "@ 116 | } 117 | 118 | Write-Verbose "query...... $query" 119 | Write-Verbose "server..... $ServerName" 120 | Write-Verbose "database... $DatabaseName" 121 | 122 | try { 123 | @(Invoke-DbaQuery -SqlInstance $ServerName -Database $DatabaseName -Query $query) 124 | } 125 | catch { 126 | Write-Error $_.Exception.Message 127 | } -------------------------------------------------------------------------------- /Get-SqlExpressInstalls.ps1: -------------------------------------------------------------------------------- 1 | #requires -module dbatools 2 | <# 3 | .SYNOPSIS 4 | Get SQL Express installations data from ConfigMgr inventory 5 | .DESCRIPTION 6 | Same as Synopsis, only longer and more wordy stuff added with beer and french fries 7 | .PARAMETER CsvFile 8 | Path to 'sqlserverversions.csv' data file 9 | .PARAMETER SqlHost 10 | SQL Server instance name 11 | .PARAMETER SiteCode 12 | Configuration Manager 3-character site code 13 | .EXAMPLE 14 | Get-SqlExpressInstalls -SqlHost "cm01" -SiteCode "P01" 15 | .NOTES 16 | B flat, C sharp, A minor 7 17 | #> 18 | function Get-SqlExpressInstalls { 19 | param ( 20 | [parameter(Mandatory=$False)] 21 | [string] $CsvFile = 'https://raw.githubusercontent.com/Skatterbrainz/sccm/master/sqlserverversions.csv', 22 | [parameter(Mandatory=$True)] 23 | [ValidateNotNullOrEmpty()] 24 | [string] $SqlHost, 25 | [parameter(Mandatory=$True)] 26 | [ValidateLength(3,3)] 27 | [string] $SiteCode 28 | ) 29 | if ($CsvFile.StartsWith('http')) { 30 | $csvdata = Invoke-RestMethod -Method Get -Uri $CsvFile -UseBasicParsing | ConvertFrom-Csv 31 | } 32 | else { 33 | if (-not(Test-Path $CsvFile)) { 34 | Write-Warning "DOA: csv file not found $csvfile" 35 | break 36 | } 37 | $csvdata = Import-Csv -Path $CsvFile 38 | } 39 | # note: the Support column below could be moved to the CSV file, but I'm lazy and dumb 40 | 41 | $query = "SELECT DISTINCT 42 | ProductName0 as ProductName, 43 | ProductVersion0 as Version, 44 | Publisher0 as Publisher, 45 | case 46 | when (ProductVersion0 like '9.%') then 'UNSUPPORTED' 47 | when (ProductVersion0 like '10.%') then 'EOL 2019/07/09' 48 | else 'SUPPORTED' end as Support, 49 | COUNT(*) AS Installs 50 | FROM 51 | v_GS_INSTALLED_SOFTWARE_CATEGORIZED 52 | WHERE 53 | ProductName0 LIKE 'Microsoft SQL Server % Express%' 54 | GROUP BY 55 | ProductName0, ProductVersion0, Publisher0 56 | ORDER BY 57 | ProductName0" 58 | 59 | try { 60 | $rows = Invoke-DbaQuery -SqlInstance $SqlHost -Database "CM_$SiteCode" -Query $query -ErrorAction SilentlyContinue 61 | foreach ($row in $rows) { 62 | $v = ($row.Version -split '\.')[0..3] 63 | if ($v[1] -in (0..5)) { 64 | if ([int]$v[0] -lt 11) { 65 | $v[1] = '00' 66 | } 67 | else { 68 | $v[1] = '0' 69 | } 70 | } 71 | if ([int]$v[0] -lt 10) { 72 | $v = $v[0..2] -join '.' 73 | } 74 | else { 75 | $v = $v -join '.' 76 | } 77 | $vn = $($csvdata | ? {$_.Version -eq $v}) 78 | $props = [ordered]@{ 79 | ProductName = $row.ProductName 80 | Version = $row.Version 81 | Version2 = $v 82 | BaseVersion = $vn.BASE 83 | ServicePack = $vn.SPK 84 | Update = $vn.UPDATE 85 | Support = $row.Support 86 | Installs = $row.Installs 87 | } 88 | New-Object PSObject -Property $props 89 | } 90 | } 91 | catch { 92 | Write-Error $Error[0].Exception.Message 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /Install-PSModule.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Install PowerShell Module from Local Folder 4 | .DESCRIPTION 5 | This script is intended for installing an offline PowerShell module 6 | into the system modules folder (%programfiles%\WindowsPowerShell\Modules) 7 | within an MDT or ConfigMgr task sequence. 8 | .EXAMPLE 9 | Install-PSModule.ps1 -Verbose 10 | .NOTES 11 | Use ```Save-Module -Name -Path ``` 12 | to download the offline copy. Then copy this script into 13 | the module folder. Create a package in ConfigMgr with or without 14 | a program. Then use Run PowerShell task to run it in a 15 | Task Sequence. 16 | 2.0.0 - DS - Rewritten to lower the cholesteral level 17 | #> 18 | [CmdletBinding()] 19 | param() 20 | try { 21 | $ModuleName = Split-Path $PSScriptRoot -Leaf 22 | Write-Verbose "module: $ModuleName" 23 | $ModuleVersion = Get-ChildItem -Path $PSScriptRoot -Directory 24 | Write-Verbose "version: $ModuleVersion" 25 | $TargetPath = Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell\Modules\$ModuleName\$ModuleVersion" 26 | if (-not (Test-Path $TargetPath)) { 27 | $SourcePath = Join-Path -Path $PSScriptRoot -ChildPath $ModuleVersion 28 | Write-Verbose "installing module" 29 | mkdir $TargetPath -Force -ErrorAction Stop | Out-Null 30 | xcopy $SourcePath\*.* $TargetPath /s 31 | $result = 0 32 | } 33 | else { 34 | Write-Verbose "module already installed" 35 | $result = 1 36 | } 37 | } 38 | catch { 39 | if ($_.Exception.Message -match 'denied'){ 40 | Write-Verbose "Access denied!" 41 | $result = -1 42 | } 43 | else { 44 | Write-Verbose $_.Exception.Message 45 | $result = -2 46 | } 47 | } 48 | finally { 49 | Write-Output $result 50 | } 51 | -------------------------------------------------------------------------------- /OSD/Copy-BootImageDrivers.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $SiteCode 4 | ) 5 | 6 | function Get-CmPsModulePath { 7 | param() 8 | $result = Get-ItemProperty "HKLM:SOFTWARE\Microsoft\SMS\Setup" | Select-Object -ExpandProperty "UI Installation Directory" 9 | $cpath = "$result\bin\ConfigurationManager.psd1" 10 | if (Test-Path $cpath) { $cpath } 11 | } 12 | 13 | function Copy-BootImageDrivers { 14 | param ( 15 | [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $SourcePath, 16 | [parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $TargetPath 17 | ) 18 | $boot = Get-CMBootImage -Id $TargetPath 19 | (Get-CMBootImage -Id $SourcePath).ReferencedDrivers | ForEach-Object { 20 | Write-Verbose "Copying $($_.Id) to $($TargetPath)" 21 | Set-CMDriver -Id $_.Id -AddBootImagePackage $boot -UpdateDistributionPointsforBootImagePackage $false 22 | } 23 | } 24 | 25 | try { 26 | Import-Module $(Get-CmPsModulePath) 27 | $oldloc = Get-Location 28 | Set-Location "$SiteCode`:" 29 | #Example use 30 | Copy-BootImageDrivers -from "ABC00123" -to "ABC00456" 31 | } 32 | catch { 33 | Write-Error $Error[0].Exception.Message 34 | } 35 | finally { 36 | Set-Location $oldloc 37 | } 38 | -------------------------------------------------------------------------------- /OSD/Export-CmTaskSequences.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Export all Task Sequences for a given SCCM site 4 | .PARAMETER TargetPath 5 | [string] path location for exporting the task sequence .ZIP files 6 | (default = user profile "Documents" folder) 7 | .PARAMETER Dependencies 8 | [switch] Indicates to export dependencies as well (not required) 9 | .PARAMETER Content 10 | [switch] Indicates to export content as well (not required) 11 | .EXAMPLE 12 | Export-CmTaskSequences.ps1 -TargetPath "C:\CMTaskSequences" 13 | .NOTES 14 | Author..... skatterbrainz.wordpress.com / GitHub / Twitter 15 | Created.... 10/26/2016 16 | Modified... TBD 17 | #> 18 | 19 | 20 | param ( 21 | [parameter(Mandatory=$False)] [string] $TargetPath = "$($env:USERPROFILE)\Documents", 22 | [parameter(Mandatory=$False)] [switch] $Dependencies, 23 | [parameter(Mandatory=$False)] [switch] $Content, 24 | [parameter(Mandatory=$False)] [switch] $ListOnly 25 | ) 26 | 27 | if (!($Dependencies)) { $Deps = $False } else { $Deps = $True } 28 | if (!($Content)) { $Cont = $False } else { $Cont = $True } 29 | $old = $pwd 30 | 31 | <# 32 | .SYNOPSIS 33 | Get-CmSiteCode was created to persevere to endeavor 34 | on the path of journey to finding that elusive beast: 35 | the site code, for this mysterious thing called a SCCM site 36 | .EXAMPLE 37 | $sitecode = Get-CmSiteCode 38 | #> 39 | 40 | function Get-CmSiteCode { 41 | $x = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\SMS" 42 | $smsp = $x.ServerAccountProvider 43 | $smsp.Substring($smsp.Length-3,3) 44 | } 45 | 46 | <# 47 | .SYNOPSIS 48 | Get-CmCmdletModule returns the [string] path location 49 | to the .PSD1 powershell module installed with SCCM 50 | .EXAMPLE 51 | $mpath = Get-CmCmdletModule 52 | #> 53 | 54 | function Get-CmCmdletModule { 55 | $result = Get-ItemProperty "HKLM:SOFTWARE\Microsoft\SMS\Setup" | 56 | Select-Object -ExpandProperty "UI Installation Directory" 57 | $cpath = "$result\bin\ConfigurationManager.psd1" 58 | if (Test-Path $cpath) { $cpath } 59 | } 60 | 61 | $cmsc = Get-CmSiteCode 62 | 63 | if (!(Get-Module "ConfigurationManager")) { 64 | $cmm = Get-CmCmdletModule 65 | if ($cmm -ne $null) { 66 | Import-Module $cmm 67 | Set-Location "$cmsc`:" 68 | } 69 | else { 70 | Write-Host "uh oh! Yo shit imploded, G." -ForegroundColor Yellow 71 | break; 72 | } 73 | } 74 | else { 75 | Set-Location "$cmsc`:" 76 | } 77 | 78 | Write-Output "requesting task sequences from site: $cmsc..." 79 | 80 | $tslist = Get-CMTaskSequence 81 | if ($tslist -ne $null) { 82 | $tscount = $tslist.Length 83 | foreach ($ts in $tslist) { 84 | $TsName = $ts.Name 85 | $TsPath = "$TargetPath\$TsName.zip" 86 | if (!($ListOnly)) { 87 | Write-Output "Exporting: $TsName..." 88 | Export-CMTaskSequence -Name "$TsName" -ExportFilePath "$TsPath" -WithDependence $Deps -WithContent $Cont -ErrorAction Continue 89 | } 90 | else { 91 | Write-Output "name: $TsName`n`texport: $TsPath" 92 | } 93 | } 94 | Write-Output "$tscount items were exported." 95 | } 96 | else { 97 | Write-Output "No task sequences were found" 98 | } 99 | cd $old -------------------------------------------------------------------------------- /OSD/Get-ComputerAdSite.ps1: -------------------------------------------------------------------------------- 1 | # thanks to https://www.powershellmagazine.com/2013/04/23/pstip-get-the-ad-site-name-of-a-computer/ 2 | function Get-ComputerAdSite { 3 | [CmdletBinding()] 4 | param ( 5 | [parameter()] [ValidateNotNullOrEmpty()] [string] $ComputerName = $env:COMPUTERNAME 6 | ) 7 | $site = nltest /server:$ComputerName /dsgetsite 2>$null 8 | if($LASTEXITCODE -eq 0){ $site[0] } 9 | } 10 | -------------------------------------------------------------------------------- /OSD/Get-NextADDeviceName.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Query AD for next available sequential device name 4 | .DESCRIPTION 5 | Query AD for next available sequential device name 6 | .PARAMETER URI 7 | URI to web service. This is typically the "http:///ConfigMgrWebService/ConfigMgr.asmx" 8 | .PARAMETER SecretKey 9 | The secret key string set during ConfigMgrWebService installation 10 | .PARAMETER Prefix 11 | Prefix portion of the device name. If desired format is "WS001" then prefix would be "WS" 12 | .PARAMETER NameLength 13 | Total length of desired device name. For "WS001" the value would be 5 14 | .EXAMPLE 15 | Get-NextADDeviceName.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "019230912309" -Prefix "WS" -NameLength 5 16 | Would return "WSxxx" where "xxx" is the next numeric suffix not found in the current AD domain 17 | .NOTES 18 | Requires the ConfigMgrWebService from SCConfigMgr.com 19 | #> 20 | [CmdletBinding()] 21 | param ( 22 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $URI, 23 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $SecretKey, 24 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $Prefix, 25 | [parameter()][ValidateRange(3,15)][int] $NameLength = 4 26 | ) 27 | $ErrorActionPreference = 'stop' 28 | try { 29 | Write-Verbose "connecting to web service at $URI" 30 | $ws = New-WebServiceProxy -Uri $URI -ErrorAction 'stop' 31 | for ($index = 1; $index -lt 100; $index++) { 32 | $nextname = $Prefix + $([string]$index).PadLeft($NameLength - $($Prefix.Length), "0") 33 | Write-Verbose "checking name: $nextname" 34 | $found = ($ws.GetADComputer($SecretKey, $nextname)).SamAccountName 35 | if (![string]::IsNullOrEmpty($found)) { 36 | Write-Verbose "name exists: $nextname" 37 | } 38 | else { 39 | return $nextname 40 | } 41 | } 42 | Write-Output "no names for this prefix available from 1 to 100" 43 | } 44 | catch { 45 | Write-Error $_.Exception.Message 46 | } -------------------------------------------------------------------------------- /OSD/Get-NextCMDeviceName.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Query CM for next available sequential device name 4 | .DESCRIPTION 5 | Query CM for next available sequential device name 6 | .PARAMETER URI 7 | URI to web service. This is typically the "http:///ConfigMgrWebService/ConfigMgr.asmx" 8 | .PARAMETER SecretKey 9 | The secret key string set during ConfigMgrWebService installation 10 | .PARAMETER Prefix 11 | Prefix portion of the device name. If desired format is "WS001" then prefix would be "WS" 12 | .PARAMETER NameLength 13 | Total length of desired device name. For "WS001" the value would be 5 14 | .EXAMPLE 15 | Get-NextCMDeviceName.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "019230912309" -Prefix "WS" -NameLength 5 16 | Would return "WSxxx" where "xxx" is the next numeric suffix not found in the CM database 17 | .NOTES 18 | Requires the ConfigMgrWebService from SCConfigMgr.com 19 | #> 20 | [CmdletBinding()] 21 | param ( 22 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $URI, 23 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $SecretKey, 24 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $Prefix, 25 | [parameter()][ValidateRange(3,15)][int] $NameLength = 4 26 | ) 27 | $ErrorActionPreference = 'stop' 28 | try { 29 | [string]$nextname = "" 30 | [int]$sfxlen = ($NameLength - $Prefix.Length) 31 | Write-Verbose "*** connecting to web service at $URI" 32 | $ws = New-WebServiceProxy -Uri $URI 33 | Write-Verbose "*** requesting next suffix for $Prefix (suffix = $sfxlen)" 34 | $found = ($ws.GetCMFirstAvailableNameSequence($SecretKey, $sfxlen, $Prefix)) 35 | if (![string]::IsNullOrEmpty($found)) { 36 | Write-Verbose "*** next available suffix = $found" 37 | $nextname = "$Prefix$found" 38 | } 39 | else { 40 | Throw "*** no suffix returned for this prefix" 41 | } 42 | try { 43 | $tsenv = New-Object -ComObject Microsoft.SMS.TSEnvironment 44 | $tsenv.Value("OSDComputerName") = $nextname 45 | Write-Verbose "*** assigned OSDComputerName = $nexname" 46 | } 47 | catch { 48 | Write-Verbose "*** not running in a task sequence" 49 | Write-Verbose "*** would have assigned OSDComputerName to $nextname" 50 | } 51 | Write-Output 0 52 | } 53 | catch { 54 | Write-Verbose $_.Exception.Message 55 | Write-Output 1 56 | } 57 | -------------------------------------------------------------------------------- /OSD/Grant-MdtSharePermissions.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [parameter(Mandatory=$True)] [string] $DeploymentShareNTFS, 3 | [parameter(Mandatory=$True)] [string] $DeploymentShareName, 4 | [parameter(Mandatory=$True)] [string] $CaptureAccount 5 | ) 6 | if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) 7 | { 8 | Write-Warning "Oops, you need to run this script from an elevated PowerShell prompt!`nPlease start the PowerShell prompt as an Administrator and re-run the script." 9 | Write-Warning "Aborting script..." 10 | Break 11 | } 12 | 13 | # Configure NTFS Permissions for the MDT Build Lab deployment share 14 | icacls $DeploymentShareNTFS /grant '"Users":(OI)(CI)(RX)' 15 | icacls $DeploymentShareNTFS /grant '"Administrators":(OI)(CI)(F)' 16 | icacls $DeploymentShareNTFS /grant '"SYSTEM":(OI)(CI)(F)' 17 | icacls "$DeploymentShareNTFS\Captures" /grant ""$CaptureAccount":(OI)(CI)(M)" 18 | 19 | # Configure Sharing Permissions for the MDT Build Lab deployment share 20 | # Note: Original uses "Change" rather than "Full" 21 | Grant-SmbShareAccess -Name $DeploymentShareName -AccountName "EVERYONE" -AccessRight Full -Force 22 | Revoke-SmbShareAccess -Name $DeploymentShareName -AccountName "CREATOR OWNER" -Force 23 | -------------------------------------------------------------------------------- /OSD/Invoke-HpBiosConfig.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Run HP BIOS config utility 4 | .DESCRIPTION 5 | Run HP BIOS config utility with fries and a coke 6 | .PARAMETER TemplatesPath 7 | Folder path where template files are stored 8 | .PARAMETER ConfigFile 9 | Name of configuration file (.txt extension) 10 | .PARAMETER Models 11 | Name of one or more models 12 | #> 13 | param ( 14 | [string] $TemplatesPath = "", 15 | [string] $ConfigFile = "COMPUTERNAME_BiosConfig.txt", 16 | [string[]] $Models = "2540","2550","2560","8530","8540","8510","7600","7700","7800","7900","8000","8100","8200","8300","Z220","Z230","Z240","HP" 17 | ) 18 | try { 19 | if (-not (Test-Path ".\BiosConfigUtility.exe")) { 20 | throw "BiosConfigUtility.exe was not found in current path" 21 | } 22 | $modelName = Get-WmiObject -Class "Win32_Computersystem" -Namespace "root\cimv2" | Select -ExpandProperty "Model" 23 | $ComputerName = Get-WmiObject -Class "Win32_Computersystem" -Namespace "root\cimv2" | Select -ExpandProperty "Name" 24 | 25 | $templateFile = "" 26 | foreach ($mx in $Models) { 27 | if ($modelName.contains($mx)) { 28 | $templateFile = Join-Path -Path $TemplatesPath -ChildPath "GetComputerName`-$mx.txt" 29 | } 30 | } 31 | if ($templateFile -eq "") { 32 | $templateFile = Join-Path -Path $TemplatesPath -ChildPath "GetComputerName.txt" 33 | $HpDetected = $False 34 | } 35 | else { 36 | $HpDetected = $True 37 | } 38 | 39 | if ($HpDetected -eq $True) { 40 | if (Test-Path $templateFile) { 41 | $templateData = Get-Content -Path $templateFile 42 | $newData = $templateData.Replace("[COMPUTERNAME]", $ComputerName) 43 | Set-Content -Path $ConfigFile -Value $newData 44 | if (Test-Path $ConfigFile) { 45 | Start-Process ".\BiosConfigUtility.exe" -ArgumentList "/setconfig:$ConfigFile" -Wait 46 | } 47 | } 48 | } 49 | } 50 | catch { 51 | Write-Error $Error[0].Exception.Message 52 | } 53 | -------------------------------------------------------------------------------- /OSD/LocMapping.csv: -------------------------------------------------------------------------------- 1 | GATEWAY,LOC,LOCNAME,COMMENT 2 | 10.0.0.1,NYC,NewYork 3 | 10.0.1.1,CHI,Chicago 4 | 10.0.2.1,SEA,Seattle 5 | -------------------------------------------------------------------------------- /OSD/Move-ComputerOU.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Move AD computer account to specified OU 4 | .DESCRIPTION 5 | Yeah, what he just said 6 | .PARAMETER OU 7 | LDAP path to move account into 8 | .PARAMETER ComputerName 9 | Name of computer account. Default is $env:COMPUTERNAME 10 | .EXAMPLE 11 | Move-ComputerOU.ps1 -OU "OU=Workstations,OU=Chicago,OU=CORP,DC=contoso,DC=local" 12 | Move local computer account into OU path 13 | .EXAMPLE 14 | Move-ComputerOU.ps1 -OU "OU=Workstations,OU=Chicago,OU=CORP,DC=contoso,DC=local" -ComputerName "WS001" 15 | Move computer WS001 to OU path 16 | .EXAMPLE 17 | Move-ComputerOU.ps1 -OU %MachinObjectOU% 18 | Move local computer account to OU specified by OSD task sequence variable 19 | .NOTES 20 | Adapted from https://ccmexec.com/2018/03/move-the-computer-to-the-correct-ou-during-osd-ps-version/ 21 | #> 22 | [CmdletBinding()] 23 | param ( 24 | [parameter()][string] $OU = "", 25 | [parameter()][string] $ComputerName = $($env:COMPUTERNAME), 26 | [parameter()][string] $DefaultOU = 'OU=DisabledComputers,OU=CORP,DC=contoso,DC=local' 27 | ) 28 | $ErrorActionPreference = 'stop' 29 | if ([string]::IsNullOrEmpty($OU)) { 30 | Write-Verbose "*** path not specified / using default path" 31 | $OU = $DefaultOU 32 | } 33 | try { 34 | $CompDN = ([ADSISEARCHER]"sAMAccountName=$ComputerName`$").FindOne().Path 35 | Write-Verbose "*** computer account found in directory: $env:COMPUTERNAME" 36 | $CompObj = [ADSI]"$CompDN" 37 | $CompObj.psbase.MoveTo([ADSI]"LDAP://$($OU)") 38 | Write-Verbose "*** computer account has been moved" 39 | Write-Output 0 40 | } 41 | catch { 42 | $_.Exception.Message ; Exit 1 43 | } -------------------------------------------------------------------------------- /OSD/OuMapping.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /OSD/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | These are a bizarre freakshow set of scripts used in conjunction with Configuration Manager (MEMCM) OSD Task Sequences to manipulate device names and/or Active Directory OU locations, during imaging. 4 | 5 | To employ these, you must include PowerShell runtime in the WinPE boot images. Tested with Windows 10 clients using Windows PowerShell 5.1 and Windows Server 2016-2019 with Windows PowerShell 5.1. 6 | 7 | Review the comments for additional details and examples within each script. 8 | 9 | # Examples 10 | 11 | ## Set-ComputerNameX.ps1 12 | 13 | * Sets OSDComputerName using standard naming glue-sniffing formats 14 | * No GUI forms, silent ninja style execution 15 | 16 | ```powershell 17 | Set-ComputerNameX.ps1 -Format Form-Serial -Delimiter Hyphen 18 | ``` 19 | 20 | (laptop w/SN "1234567890") returns "LT-67890" 21 | 22 | ```powershell 23 | Set-ComputerNameX.ps1 -Format Form-Serial -Delimiter Hyphen -NameLength 5 24 | ``` 25 | 26 | (laptop w/SN "1234567890") returns "LT-90" 27 | 28 | ```powershell 29 | Set-ComputerNameX.ps1 -Format Form-Serial -Delimiter Hyphen -TrimSerialFrom Right 30 | ``` 31 | 32 | (desktop w/SN "1234567890") returns "WS-12345" 33 | 34 | ```powershell 35 | Set-ComputerNameX.ps1 -Format Form-Serial -WorkstationPrefix "D" -NameLength 6 36 | ``` 37 | 38 | (desktop w/SN "1234567890") returns "D67890" 39 | 40 | ## Set-OSDComputerName6.ps1 41 | 42 | * Another GUI-based glue-sniffing, paint-fume inspired device naming script 43 | * Includes Department code using a string array 44 | * Requires desktops-ous.txt and laptops-ous.txt 45 | 46 | ```powershell 47 | Set-OSDComputerName6.ps1 -Verbose 48 | ``` 49 | 50 | Default options. Returns name from WPF form inputs: Prefix (Dept) + SerialNum + Suffix (optional). If device has serial number "1234567890" and department "ITS" is chosen, the result name would be "ITS-12345678" 51 | 52 | ```powershell 53 | Set-OSDComputerName6.ps1 -MaxSerialLen 5 -DefaulOU "OU=Disabled,OU=Computers,OU=CORP,DC=contoso,DC=local" -DepartmentsList ("ITS","ACC","EXT","FIN","HRS") -DefaultDeptCode "ITS" 54 | ``` 55 | 56 | Displays form with department codes list in Prefix select-list, last 7 chars of SerialNumber, and blank Suffix. If device has serial number "1234567890" and department "ITS" is chose, the result name would be "ITS-12345" 57 | 58 | ## Test-CMDeviceNameADConflict.ps1 59 | 60 | ```powershell 61 | Test-CMDeviceNameADConflict.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12352342" -TSVariable "ACCTEXISTS" 62 | ``` 63 | 64 | Sets TS variable "ACCTEXISTS" to "TRUE" if %OSDComputerName% value exists in Active Directory domain 65 | 66 | ```powershell 67 | Test-CMDeviceNameADConflict.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12352342" -TSVariable "ACCTEXISTS" -Delete 68 | ``` 69 | 70 | Sets TS variable "ACCTEXISTS" to "FALSE" if %OSDComputerName% value is found and deleted in Active Directory domain 71 | 72 | ```powershell 73 | Test-CMDeviceNameADConflict.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12352342" -TSVariable "ACCTEXISTS" -ComputerName "WS004" 74 | ``` 75 | 76 | Sets TS variable "ACCTEXISTS" to "TRUE" if computer "WS004"" exists in Active Directory domain. This is mainly for testing outside of a task sequence environment 77 | 78 | ## Set-ComputerNameIncrementAD.ps1 79 | 80 | * Query AD for next available sequential device name, updates TS var OSDComputerName 81 | * Requires ConfigMgr Web Service (https://www.scconfigmgr.com) 82 | 83 | ```powershell 84 | Set-ComputerNameIncrementAD.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "019230912309" -Prefix "WS" -NameLength 5 85 | ``` 86 | 87 | If WS001 and WS002 exist in AD, but not WS003, then this will return WS003 88 | 89 | ## Set-ComputerNameIncrementCM.ps1 90 | 91 | * Query CM database for next available sequential device name, updates TS var OSDComputerName 92 | * Requires ConfigMgr Web Service (https://www.scconfigmgr.com) 93 | 94 | ```powershell 95 | Set-ComputerNameIncrementCM.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "019230912309" -Prefix "WS" -NameLength 5 96 | ``` 97 | 98 | If WS001 and WS002 exist in the CM database, but not WS003, then this would return WS003 99 | 100 | ## Set-ComputerOUPath.ps1 101 | 102 | * Set AD OU Path in CM OSD Task Sequence using IP Gateway 103 | * Requires file: oulocations.txt 104 | 105 | ```powershell 106 | Set-ComputerOUPath.ps1 107 | ``` 108 | 109 | Look for matching row in oulocations.txt using actual IPv4 gateway 110 | 111 | ```powershell 112 | Set-ComputerOUPath.ps1 -Gateway "192.168.3.1" 113 | ``` 114 | 115 | Look for matching row in oulocations.txt using forced IPv4 gateway value 116 | 117 | ```powershell 118 | Set-ComputerOUPath.ps1 -DataFile "oulocations2.txt" 119 | ``` 120 | 121 | Look for matching row in custom data file using actual IPv4 gateway. Default file is oulocations.txt 122 | 123 | ## Move-ComputerOU.ps1 124 | 125 | ```powershell 126 | Move-ComputerOU.ps1 -OU "OU=Workstations,OU=Chicago,OU=CORP,DC=contoso,DC=local" 127 | ``` 128 | 129 | Move local computer account into OU path 130 | ```powershell 131 | Move-ComputerOU.ps1 -OU "OU=Workstations,OU=Chicago,OU=CORP,DC=contoso,DC=local" -ComputerName "WS001" 132 | ``` 133 | 134 | Move computer WS001 to OU path 135 | 136 | ```powershell 137 | Move-ComputerOU.ps1 -OU %MachinObjectOU% 138 | ``` 139 | 140 | Move local computer account to OU specified by OSD task sequence variable 141 | -------------------------------------------------------------------------------- /OSD/Send-TSNotifications.md: -------------------------------------------------------------------------------- 1 | # Send Task Sequence Success/Fail Notifications 2 | 3 | ## Notes 4 | 5 | * Inspired heavily and in all the right ways by the incomparable Nathan Zienhert (@theznerd) 6 | * TS Group "Failure Group" 7 | * Condition: (TSVar) ```_SMSTSLastActionSucceeded equals "false"``` 8 | * Task Sequence Step "Capture Failure Conditions" 9 | * SET TSVar ```FailedStepName = "%_SMSTSLastActionName%"``` 10 | * SET TSVar ```FailedStepReturnCode = "%_SMSTSLastActionRetCode%"``` 11 | * SET TSVar ```AllStepsSucceeded = "False"``` 12 | * Set TS Variable "(OSDResults) - Failure" 13 | * SET TSVar "OSDResults" = "Failure" 14 | * Connect to Network Folder 15 | * Map drive to Z: 16 | * Create Log Folder 17 | * ```cmd.exe /c md Z:\%OSDComputerName%\``` 18 | * Run PSScript: Send Deployment Failed Notification (Email) -- below 19 | * Run PSScript: Send Deployment Failed Notification (Teams) 20 | * TS Group "Success Group" 21 | * Set TSVar "OSDResults" = "Success" 22 | * TS Group "Cleanup and Logging" 23 | * Run PSScript: OSDResultsTally.ps1 by Mike Marable (2018) 24 | * Params: -Record "%OSDResults%" 25 | 26 | ## Script 27 | 28 | ```powershell 29 | [CmdletBinding()] 30 | param ( 31 | [parameter(Mandatory)][string] $Type, 32 | [parameter()][string] $To = "", 33 | [parameter()][string] $Image, 34 | [parameter()][string] $SiteServer = "cm01.contoso.com", 35 | [parameter()][string] $smtpServer = "mail.contoso.com" 36 | [parameter()][string] $smtpFrom = "sender@contoso.com" 37 | ) 38 | 39 | $dateTime = Get-Date -f 'MM/dd/yyyy HH:mm:ss tt' 40 | 41 | $computerName = (New-Object -COMObject Microsoft.SMS.TSEnvironment).Value("OSDComputerName") 42 | $lastAction = (New-Object -COMObject Microsoft.SMS.TSEnvironment).Value("FailedStepName") 43 | $TaskSequence = (New-Object -COMObject Microsoft.SMS.TSEnvironment).Value("_SMSTSPackageName") 44 | $ipconfig = ipconfig /all 45 | $dns = ping $siteserver 46 | 47 | function Send-Mail { 48 | param ( 49 | [parameter(Mandatory)][string] $Body, 50 | [parameter(Mandatory)][string] $Subject 51 | ) 52 | $smtp = New-Object Net.Mail.SmtpClient($smtpServer) 53 | $message = New-Object Net.Mail.MailMessage 54 | $message.To.Add($to) 55 | $message.From = $smtpFrom 56 | $message.Subject = $subject 57 | $message.Body = $body 58 | $smtp.Send($message) 59 | } 60 | 61 | switch ($type) { 62 | 'DeploymentFailure' { 63 | $pbody = @" 64 | Task Sequence $TaskSequence failed to complete. 65 | 66 | Computer: $computerName 67 | Failed Step: $LastAction 68 | 69 | Please review the logs located in \\$siteServer\OSDErrorLogs\$computerName 70 | for further information. 71 | "@ 72 | $psubject = "SCCM TS ALERT: Task Sequence Failure" 73 | } 74 | 'DeploymentComplete' { 75 | $pbody = @" 76 | The image deployment process for $computerName completed at $dateTime 77 | This computer was imaged with TS version: $image 78 | "@ 79 | $psubject = "SCCM TS Notice: Task Sequence Completed Successfully" 80 | } 81 | } # switch 82 | Send-Mail -body $pbody -subject $psubject 83 | ``` 84 | -------------------------------------------------------------------------------- /OSD/Set-ComputerNameIncrementAD.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Query AD for next available sequential device name 4 | .DESCRIPTION 5 | Query AD for next available sequential device name 6 | .PARAMETER URI 7 | URI to web service. This is typically the "http:///ConfigMgrWebService/ConfigMgr.asmx" 8 | .PARAMETER SecretKey 9 | The secret key string set during ConfigMgrWebService installation 10 | .PARAMETER Prefix 11 | Prefix portion of the device name. If desired format is "WS001" then prefix would be "WS" 12 | .PARAMETER NameLength 13 | Total length of desired device name. For "WS001" the value would be 5 14 | .EXAMPLE 15 | Set-ComputerNameIncrementAD.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "019230912309" -Prefix "WS" -NameLength 5 16 | If WS001 and WS002 exist in AD, but not WS003, then this will return WS003 17 | .NOTES 18 | Requires the ConfigMgrWebService from SCConfigMgr.com 19 | #> 20 | [CmdletBinding()] 21 | param ( 22 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $URI, 23 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $SecretKey, 24 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $Prefix, 25 | [parameter()][ValidateRange(3,15)][int] $NameLength = 4 26 | ) 27 | 28 | function Get-NextADDeviceName { 29 | param() 30 | try { 31 | Write-Verbose "connecting to web service at $URI" 32 | $ws = New-WebServiceProxy -Uri $URI -ErrorAction 'stop' 33 | for ($index = 1; $index -lt 100; $index++) { 34 | $nextname = $Prefix + $([string]$index).PadLeft($NameLength - $($Prefix.Length), "0") 35 | Write-Verbose "checking name: $nextname" 36 | $found = ($ws.GetADComputer($SecretKey, $nextname)).SamAccountName 37 | if (![string]::IsNullOrEmpty($found)) { 38 | Write-Verbose "name exists: $nextname" 39 | } 40 | else { 41 | Write-Verbose "name available: $nextname" 42 | return $nextname 43 | } 44 | } 45 | Write-Output "no names for this prefix available from 1 to 100" 46 | } 47 | catch { 48 | Write-Error $_.Exception.Message 49 | } 50 | } 51 | 52 | $cn = Get-NextADDeviceName 53 | 54 | try { 55 | $tsenv = New-Object -ComObject Microsoft.SMS.TSEnvironment 56 | $tsenv.Value("OSDComputerName") = $cn 57 | Write-Verbose "*** assigned OSDComputerName = $cn" 58 | } 59 | catch { 60 | Write-Verbose "*** not running in a task sequence" 61 | Write-Verbose "*** would have assigned OSDComputerName to $cn" 62 | } 63 | -------------------------------------------------------------------------------- /OSD/Set-ComputerNameIncrementCM.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Query CM for next available sequential device name 4 | .DESCRIPTION 5 | Query CM for next available sequential device name 6 | .PARAMETER URI 7 | URI to web service. This is typically the "http:///ConfigMgrWebService/ConfigMgr.asmx" 8 | .PARAMETER SecretKey 9 | The secret key string set during ConfigMgrWebService installation 10 | .PARAMETER Prefix 11 | Prefix portion of the device name. If desired format is "WS001" then prefix would be "WS" 12 | .PARAMETER NameLength 13 | Total length of desired device name. For "WS001" the value would be 5 14 | .EXAMPLE 15 | Set-ComputerNameIncrementCM.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "019230912309" -Prefix "WS" -NameLength 5 16 | If WS001 and WS002 exist in the CM database, but not WS003, then this would return WS003 17 | .NOTES 18 | Requires the ConfigMgrWebService from SCConfigMgr.com 19 | #> 20 | [CmdletBinding()] 21 | param ( 22 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $URI, 23 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $SecretKey, 24 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $Prefix, 25 | [parameter()][ValidateRange(3,15)][int] $NameLength = 4 26 | ) 27 | 28 | function Get-NextCMDeviceName { 29 | param() 30 | function Get-NextADDeviceName { 31 | param() 32 | try { 33 | Write-Verbose "connecting to web service at $URI" 34 | $ws = New-WebServiceProxy -Uri $URI -ErrorAction 'stop' 35 | [int]$sfxlen = ($NameLength - $Prefix.Length) 36 | Write-Verbose "*** requesting next suffix for $Prefix (suffix = $sfxlen)" 37 | $found = ($ws.GetCMFirstAvailableNameSequence($SecretKey, $sfxlen, $Prefix)) 38 | if (![string]::IsNullOrEmpty($found)) { 39 | $nextname = "$Prefix$found" 40 | Write-Verbose "*** next available name = $nextname" 41 | return $nextname 42 | } 43 | else { 44 | Throw "*** no suffix returned for this prefix" 45 | } 46 | Write-Output "no names for this prefix available from 1 to 100" 47 | } 48 | catch { 49 | Write-Error $_.Exception.Message 50 | } 51 | } 52 | } 53 | 54 | $cn = Get-NextCMDeviceName 55 | 56 | try { 57 | $tsenv = New-Object -ComObject Microsoft.SMS.TSEnvironment 58 | $tsenv.Value("OSDComputerName") = $cn 59 | Write-Verbose "*** assigned OSDComputerName = $cn" 60 | } 61 | catch { 62 | Write-Verbose "*** not running in a task sequence" 63 | Write-Verbose "*** would have assigned OSDComputerName to $cn" 64 | } 65 | -------------------------------------------------------------------------------- /OSD/Set-ComputerNameX.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Yet another device naming script for OSD 4 | .DESCRIPTION 5 | Yet another device naming script for OSD and yes I know thats a repeat 6 | .PARAMETER Format 7 | Naming format: Serial or Form-Serial (default: Serial) 8 | Serial = BIOS Serial Number 9 | Form-Serial = Form-Factor + BIOS Serial Number 10 | .PARAMETER WorkstationPrefix 11 | Default prefix for Desktop/Workstation devices: D, DT, W, WS (default: WS) 12 | .PARAMETER LaptopPrefix 13 | Default prefix for Laptop devices: L, LT (default: LT) 14 | .PARAMETER NameLength 15 | Maximum characters to limit new device name (truncate if needed). Default is 8 16 | .PARAMETER TrimSerialFrom 17 | Which side of BIOS Serial Number to trim when necessar: Left or Right (default: Left) 18 | .PARAMETER Delimiter 19 | Option for joining naming components when -Format is Form-Serial: None, Hyphen, Underscore (default: None) 20 | Hyphen: Form-SerialNumber 21 | Underscore: Form_SerialNumber 22 | None: FormSerialNumber 23 | .EXAMPLE 24 | Set-ComputerNameX.ps1 -Format Form-Serial -Delimiter Hyphen 25 | (laptop) "LT-67890" 26 | .EXAMPLE 27 | Set-ComputerNameX.ps1 -Format Form-Serial -Delimiter Hyphen -NameLength 5 28 | (laptop) "LT-90" 29 | .EXAMPLE 30 | Set-ComputerNameX.ps1 -Format Form-Serial -Delimiter Hyphen -TrimSerialFrom Right 31 | (laptop) "LT-12345" 32 | .EXAMPLE 33 | Set-ComputerNameX.ps1 -Format Form-Serial 34 | (laptop) "LT123456" 35 | #> 36 | [CmdletBinding()] 37 | param ( 38 | [parameter()][ValidateSet('Serial','Form-Serial')][string] $Format = 'Serial', 39 | [parameter()][ValidateSet('D','DT','W','WS')][string] $WorkstationPrefix = 'WS', 40 | [parameter()][ValidateSet('L','LT')][string] $LaptopPrefix = 'L', 41 | [parameter()][int] $NameLength = 8, 42 | [parameter()][ValidateSet('Left','Right')][string] $TrimSerialFrom = 'Left', 43 | [parameter()][ValidateSet('None','Hyphen','Underscore')][string] $Delimiter = 'None' 44 | ) 45 | $ErrorActionPreference = 'stop' 46 | 47 | function Get-FormFactorCode { 48 | [CmdletBinding()] 49 | param () 50 | $cff = $(Get-CimInstance -ClassName Win32_SystemEnclosure -Namespace root\cimv2).ChassisTypes 51 | # ignore docks/port replicators which return an array rather than one value 52 | if ($cff.Count -gt 1) { 53 | $cff = $cff[0] 54 | Write-Verbose "*** filtering out duplicate for external device" 55 | } 56 | Write-Verbose "*** chassis type = $cff" 57 | # as of Q1-2018, codes are from 1 to 36 58 | # see https://blogs.technet.microsoft.com/brandonlinton/2017/09/15/updated-win32_systemenclosure-chassis-types/ 59 | # desktops 60 | if ($cff -in (3..7)+(13,34,35)) { $ff = $WorkstationPrefix } 61 | # laptops 62 | elseif ($cff -in (10,11,12,14)+(15..30)+(31,32,33,36)) { $ff = $LaptopPrefix } 63 | # servers, but whatever, I do what I want! 64 | elseif ($cff -in (17..24)) { $ff = $WorkstationPrefix } 65 | # unknown 66 | else { $ff = $WorkstationPrefix } 67 | Write-Output $ff 68 | } 69 | 70 | try { 71 | $result = "" 72 | # get serial number 73 | $sn = $(Get-CimInstance -ClassName Win32_SystemEnclosure -Namespace root\cimv2).SerialNumber 74 | Write-Verbose "*** serial number... $sn" 75 | 76 | if ($sn.Length -gt $NameLength) { 77 | if ($TrimSerialFrom -eq 'Left') { 78 | $curlen = $sn.Length 79 | $sn = $sn.Substring($curlen - $NameLength, $NameLength) 80 | } 81 | else { 82 | $sn = $sn.Substring(0, $NameLength) 83 | } 84 | } 85 | Write-Verbose "*** trimmed value... $sn" 86 | if ($Format -eq 'Serial') { 87 | $result = $sn 88 | } 89 | else { 90 | $pfx = Get-FormFactorCode -Verbose:$VerbosePreference 91 | switch ($Delimiter) { 92 | 'Hyphen' {$result = "$pfx`-$sn"} 93 | 'Underscore' {$result = "$pfx`_$sn"} 94 | Default {$result = "$pfx$sn"} 95 | } 96 | } 97 | try { 98 | $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment 99 | # suppress progress form only if presenting a new UI 100 | # $tsui = New-Object -COMObject Microsoft.SMS.TSProgressUI 101 | Write-Verbose "*** assigning OSDComputerName to $result" 102 | $tsenv.Value("OSDComputerName") = $result 103 | } 104 | catch { 105 | Write-Verbose "*** not running in a task sequence environment" 106 | } 107 | } 108 | catch { 109 | Write-Error $Error[0].Exception.Message 110 | } 111 | finally { 112 | Write-Output $result 113 | } 114 | -------------------------------------------------------------------------------- /OSD/Set-ComputerOUPath.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Set AD OU Path in CM OSD Task Sequence using IP Gateway 4 | .DESCRIPTION 5 | Set AD OU Path in CM OSD Task Sequence using IP Gateway 6 | .PARAMETER Gateway 7 | Forced IP gateway value (for testing only). Default is empty string 8 | .PARAMETER DataFile 9 | Name of OU mapping txt file. Must be in same path as script. Default is oulocations.txt 10 | .PARAMETER WorkstationsOU 11 | Name of leaf OU for desktops and workstations. Default is "Workstations" 12 | .PARAMETER LaptopsOU 13 | Name of leaf OU for Laptops. Default is "Laptops" 14 | .PARAMETER ServersOU 15 | Name of leaf OU for servers. Default is "Servers" 16 | .EXAMPLE 17 | Set-ComputerOUPath.ps1 18 | Look for matching row in oulocations.txt using actual IPv4 gateway 19 | .EXAMPLE 20 | Set-ComputerOUPath.ps1 -Gateway "192.168.3.1" 21 | Look for matching row in oulocations.txt using forced IPv4 gateway value 22 | .EXAMPLE 23 | Set-ComputerOUPath.ps1 -DataFile "mygateways.txt" 24 | Look for matching row in custom data file using actual IPv4 gateway 25 | #> 26 | [CmdletBinding()] 27 | param ( 28 | [parameter()][string] $Gateway = "", 29 | [parameter()][string] $WorkstationsOU = "Workstations", 30 | [parameter()][string] $LaptopsOU = "Laptops", 31 | [parameter()][string] $ServersOU = "Servers", 32 | [parameter()][ValidateNotNullOrEmpty()][string] $DataFile = "oulocations.txt" 33 | ) 34 | 35 | $cfgfile = Join-Path $PSScriptRoot $DataFile 36 | $result = 0 37 | 38 | function Get-FormFactorCode { 39 | [CmdletBinding()] 40 | param () 41 | try { 42 | $mn = (Get-CimInstance -Namespace root/cimv2 -Class Win32_ComputerSystem).Model 43 | $ct = ((Get-CimInstance -Namespace root/cimv2 -Class Win32_SystemEnclosure).ChassisTypes) 44 | # ignore docks/port replicators which often 45 | # return an array rather than one value 46 | if ($mn -match 'Virtual') { $ff = 'V' } 47 | else { 48 | if ($ct.Count -gt 1) { 49 | $ct = $ct[0] 50 | Write-Verbose "*** multiple values returned" 51 | } 52 | Write-Verbose "*** wmi chassis type = $ct" 53 | switch ($ct) { 54 | {($_ -in (3,4,5,6,7,13,15,24,35))} { $ff = 'D' } 55 | {($_ -in (8,9,10,12,14,18,21))} { $ff = 'L' } 56 | {($_ -in (17,19,20,22,23,25,26,27,28,29))} { $ff = 'S' } 57 | {($_ -in (30,31,32))} { $ff = 'T' } 58 | {($_ -in (11))} { $ff = 'M' } 59 | {($_ -in (1,2,33))} { $ff = 'O' } 60 | {($_ -in (34))} { $ff = 'E' } 61 | } 62 | } 63 | Write-Output $ff 64 | } 65 | catch {} 66 | } 67 | 68 | try { 69 | if (!(Test-Path $cfgfile)) { 70 | throw "file not found: $cfgfile" 71 | } 72 | Write-Verbose "*** reading data from $cfgfile" 73 | $cfgdata = Get-Content -Path $cfgfile 74 | if ([string]::IsNullOrEmpty($Gateway)) { 75 | $Gateway = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration | 76 | Where-Object {$_.IPEnabled -eq $True -and $_.DefaultIPGateway -ne '::'} | 77 | Select-Object -ExpandProperty DefaultIPGateway 78 | } 79 | Write-Verbose "*** current IP gateway is $Gateway" 80 | $i = 0 81 | while ([string]::IsNullOrEmpty($oupath)) { 82 | $row = $cfgdata[$i] -split ':' 83 | if ($row[0] -eq $Gateway) { 84 | $oupath = $row[2] 85 | } 86 | $i++ 87 | } 88 | if ([string]::IsNullOrEmpty($oupath)) { 89 | throw "no matching value found" 90 | } 91 | else { 92 | $ffcode = Get-FormFactorCode 93 | switch ($ffcode) { 94 | 'D' {$oupath = "OU=$WorkstationsOU,$oupath"} 95 | 'V' {$oupath = "OU=$WorkstationsOU,$oupath"} 96 | 'L' {$oupath = "OU=$LaptopsOU,$oupath"} 97 | 'S' {$oupath = "OU=$ServersOU,$oupath"} 98 | default { throw "no mapping for form factor $ffcode" } 99 | } 100 | } 101 | try { 102 | $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment -ErrorAction SilentlyContinue 103 | $tsActive = $true 104 | } 105 | catch {} 106 | if ($tsActive) { 107 | # suppress progress form only if presenting a new UI 108 | # $tsui = New-Object -COMObject Microsoft.SMS.TSProgressUI 109 | Write-Verbose "*** assigning OSDDomainOUName to $oupath" 110 | $tsenv.Value("OSDDomainOUName") = $oupath 111 | } 112 | else { 113 | Write-Verbose "*** running in interactive mode ***" 114 | Write-Verbose "*** OSDDomainOUName = $oupath" 115 | } 116 | } 117 | catch { 118 | $result = -1 119 | Write-Verbose $Error[0].Exception.Message 120 | } 121 | finally { 122 | Write-Output $result 123 | } -------------------------------------------------------------------------------- /OSD/Set-OSDComputerName3.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | .\OSDComputerName3.ps1 4 | .NOTES 5 | written by me. :D 6 | #> 7 | 8 | $chType = Get-WmiObject -Class Win32_SystemEnclosure | Select-Object -ExpandProperty ChassisTypes 9 | $serialNum = Get-WmiObject -Class Win32_SystemEnclosure | Select-Object -ExpandProperty SerialNumber 10 | 11 | Write-Output "INFO: wmi chassistypes = $chType" 12 | Write-Output "INFO: wmi serialnumber = $serialNum" 13 | 14 | switch ($chType) { 15 | 3 { $prefix = "D" } 16 | 4 { $prefix = "D" } 17 | 5 { $prefix = "D" } 18 | 6 { $prefix = "D" } 19 | 7 { $prefix = "D" } 20 | 8 { $prefix = "L" } 21 | 9 { $prefix = "L" } 22 | 10 { $prefix = "L" } 23 | 11 { $prefix = "M" } 24 | 13 { $prefix = "D" } 25 | 14 { $prefix = "L" } 26 | 15 { $prefix = "D" } 27 | 16 { $prefix = "D" } 28 | 17 { $prefix = "S" } 29 | 18 { $prefix = "X" } 30 | 19 { $prefix = "S" } 31 | 20 { $prefix = "S" } 32 | 21 { $prefix = "S" } 33 | 22 { $prefix = "S" } 34 | 23 { $prefix = "S" } 35 | 24 { $prefix = "S" } 36 | default { $prefix = "U" } 37 | } 38 | try { 39 | if ($serialNum.Length -gt 8) { 40 | $sn = $serialNum.Substring($serialNum.length -8, 8) 41 | } 42 | else { 43 | $sn = $serialNum 44 | } 45 | $newName = $prefix +"-$sn" 46 | Write-Output "INFO: New Name = $newName" 47 | 48 | $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment 49 | $tsenv.Value("OSDComputerName") = $newName 50 | } 51 | catch { 52 | Write-Output $Error[0].Exception.Message 53 | } 54 | -------------------------------------------------------------------------------- /OSD/Set-OSDComputerName4.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Set OSDComputerName variable to custom format 4 | .DESCRIPTION 5 | Set name format (LocationCode + FormatFactor + SerialNumber) 6 | Example "NYCD12345678901" ("NYC" + "D" + "12345678901") 7 | .PARAMETER LocationFile 8 | Name of file containing location/gateway mapping information (same folder path as script) 9 | .PARAMETER TrimFrom 10 | Which side (left/right) to trim serialnumber when exceeds 15 overall 11 | #> 12 | [CmdletBinding()] 13 | param ( 14 | [parameter()] [string] $LocationFile = $(Join-Path $PSScriptRoot 'locations.txt'), 15 | [parameter()] [ValidateSet('Left','Right')] [string] $TrimFrom = 'Left' 16 | ) 17 | Write-Verbose "script version 1909.11" 18 | 19 | #region internal functions 20 | 21 | function Get-SerialNumber { 22 | [CmdletBinding()] 23 | param () 24 | $csn = Get-WmiObject -Class Win32_SystemEnclosure | Select-Object -ExpandProperty SerialNumber 25 | if ($csn.Count -gt 1) { $csn = $csn[0] } 26 | Write-Verbose "full serial number = $csn" 27 | if ($csn.Length -gt 15) { 28 | Write-Verbose "trim side = $TrimFrom" 29 | if ($TrimFrom -eq 'Left') { 30 | $csn = $csn.Substring($csn.Length - 15) 31 | } 32 | else { 33 | $csn = $csn.Substring(0, 15) 34 | } 35 | } 36 | Write-Verbose "constrained serial number = $csn" 37 | Write-Output $csn 38 | } 39 | 40 | function Get-FormFactorCode { 41 | [CmdletBinding()] 42 | param () 43 | $cff = Get-WmiObject -Class Win32_SystemEnclosure | Select-Object -ExpandProperty ChassisTypes 44 | # ignore docks/port replicators which return an array rather than one value 45 | if ($cff.Count -gt 1) { $cff = $cff[0] } 46 | Write-Verbose "chassis type is $cff" 47 | # as of Q1-2018, codes are from 1 to 36 48 | # see https://blogs.technet.microsoft.com/brandonlinton/2017/09/15/updated-win32_systemenclosure-chassis-types/ 49 | # desktops 50 | if ($cff -in (3..7)+(13,34,35)) { $ff = 'D' } 51 | # laptops 52 | elseif ($cff -in (15..30)+(10,11,12,14,31,32,33,36)) { $ff = 'L' } 53 | # servers 54 | elseif ($cff -in (17..24)) { $ff = 'S' } 55 | # unknown 56 | else { $ff = 'X' } 57 | Write-Verbose "form factor code: $ff" 58 | Write-Output $ff 59 | } 60 | 61 | function Get-LocationCode { 62 | [CmdletBinding()] 63 | param ( 64 | [parameter(Mandatory=$False, HelpMessage="Default Location Code")] 65 | [string] $DefaultLoc = "", 66 | [parameter(Mandatory=$False, HelpMessage="Path to Location codes text file")] 67 | [string] $DataFile = $LocationFile 68 | ) 69 | try { 70 | $gwa = Get-WmiObject -Class Win32_NetworkAdapterConfiguration | 71 | Where-Object {$_.IPEnabled -eq $True -and $_.DefaultIPGateway -ne '::'} | 72 | Select-Object -ExpandProperty DefaultIPGateway 73 | <# 74 | format of location data is as follows: 75 | GATEWAY=FULLNAME,ABBREV (no headings in file, shown here just for explanation) 76 | 10.0.0.1=NEWYORK,NYC 77 | 10.2.0.1=LOSANGELES,LAX 78 | #> 79 | if (!(Test-Path -Path $DataFile)) { 80 | Write-Verbose "data file not found: $DataFile" 81 | Write-Output "" 82 | break 83 | } 84 | $shortname = "" 85 | $dataset = Get-Content -Path $DataFile 86 | if ($dataset.length -gt 0) { 87 | Write-Verbose "data loaded from text file" 88 | } 89 | foreach ($row in $dataset) { 90 | $rowdata = $row -split '=' 91 | $gateway = $rowdata[0] 92 | if ($gateway -eq $gwa) { 93 | $location = $rowdata[1] 94 | $fullname = ($location -split ',')[0] 95 | $shortname = ($location -split ',')[1] 96 | Write-Verbose "location: $fullname" 97 | Write-Verbose "shortname: $shortname" 98 | break 99 | } 100 | } 101 | if ($shortname -eq "") { $shortname = $DefaultLoc } 102 | Write-Verbose "location code is: $shortname" 103 | Write-Output $shortname 104 | } 105 | catch { 106 | Write-Error $Error[0].Exception.Message 107 | Write-Output "" 108 | } 109 | } 110 | 111 | #endregion internal functions 112 | 113 | [string]$sn = Get-SerialNumber 114 | [string]$fc = Get-FormFactorCode 115 | [string]$lc = Get-LocationCode 116 | Write-Verbose "serial number = $sn" 117 | Write-Verbose "form factor code = $fc" 118 | Write-Verbose "location code = $lc" 119 | $tempname = $lc + $fc + $sn 120 | Write-Verbose "temp name = $tempname" 121 | $newname = $tempname 122 | if ($tempname.Length -gt 15) { 123 | $newname = $tempname.Substring(0,15) 124 | } 125 | Write-Verbose "new name = $newname" 126 | # try to get TS environment if available 127 | try { 128 | $tsenv = New-Object -COMObject "Microsoft.SMS.TSEnvironment" -ErrorAction SilentlyContinue 129 | } 130 | catch { 131 | Write-Verbose "no task sequence running" 132 | } 133 | if ($null -ne $tsenv) { 134 | Write-Verbose "task sequence environment is active" 135 | $OSDComputername = $tsenv.Value("OSDComputername") 136 | Write-Verbose "current OSDcomputername = $OSDComputername" 137 | $tsenv.Value("OSDComputername") = $newname 138 | Write-Output "Set OSDComputername = $($tsenv.value("OSDComputername"))" 139 | } 140 | else { 141 | Write-Verbose "not running in a task sequence" 142 | Write-Output "OSDComputer would be set to $newname" 143 | } 144 | -------------------------------------------------------------------------------- /OSD/Show-TsVars.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Show Task Sequence Variable Assignments 4 | 5 | .DESCRIPTION 6 | This will write out the current SCCM OSD Task Sequence variable assignments 7 | during OSD execution. Insert into Task sequence where desired. Enable or disable 8 | each reference - or - set a TS variable to toggle this script on or off in the Task Sequence 9 | 10 | .NOTES 11 | Original author: Michael Niehaus 12 | Lazy hack: David Stein 13 | 14 | .LINK 15 | https://blogs.technet.microsoft.com/mniehaus/2010/04/26/dumping-task-sequence-variables/ 16 | 17 | .EXAMPLE 18 | .\Show-TsVars.ps1 19 | 20 | #> 21 | try { 22 | $TSenv = New-Object -COMObject Microsoft.SMS.TSEnvironment 23 | $logPath = $TSenv.Value("_SMSTSLogPath") 24 | $logFile = Join-Path -Path $logPath" -ChildPath "$($myInvocation.MyCommand).log" 25 | Start-Transcript $logFile 26 | $TSenv.GetVariables() | Foreach-Object { Write-Host "$_ = $($tsenv.Value($_))" } 27 | Stop-Transcript 28 | } 29 | catch { 30 | Write-Output $Error[0].Exception.Message 31 | } 32 | -------------------------------------------------------------------------------- /OSD/TaskSequenceGoodies.md: -------------------------------------------------------------------------------- 1 | # Task Sequence Goodies 2 | 3 | ## Disable Edge Desktop Shortcut 4 | 5 | *Run Command* 6 | 7 | ``` 8 | reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer /v "DisableEdgeDesktopShortcutCreation" /t REG_DWORD /d "1" /f 9 | ``` 10 | 11 | ## Enable OneDrive Sync 12 | 13 | *Run Command* 14 | 15 | ``` 16 | reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\OneDrive /v DisableFileSyncNGSC /t REG_DWORD /d 0 /f 17 | ``` 18 | 19 | ## Capture Start Time as OSD Variable 20 | 21 | *Run Command* 22 | 23 | ``` 24 | powershell (New-Object -COMObject Microsoft.SMS.TSEnvironment).Value("OSDStartInfo") = (Get-Date -f 'dd-MMM-yyyy hh:mm:ss') 25 | ``` 26 | 27 | ## Move Computer OU 28 | 29 | ```powershell 30 | param ( 31 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $OuPath 32 | ) 33 | try { 34 | $compDN = $([adsisearcher]"samaccountname=$($env:COMPUTERNAME)").FindOne().Path 35 | $compObj = [adsi]$compDN 36 | $compObj.psbase.MoveTo([adsi]"LDAP://$($OuPath)") 37 | } 38 | catch { 39 | $_.Exception.Message ; Exit 1 40 | } 41 | ``` 42 | 43 | ## Send Notification Email 44 | 45 | * Name: Send TS Deployment Notification 46 | * Type: Run PowerShell Script 47 | * Config: Pkg/script: Send-TSCompleteNotification.ps1 48 | * Args: -To "address" -Image "%_SMSTSPackageName%" -Type "DeploymentFailure" 49 | -------------------------------------------------------------------------------- /OSD/Test-CMDeviceNameADConflict.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Checks if Computer Name already exists in AD domain 4 | .DESCRIPTION 5 | Checks if Computer Name already exists in AD domain. 6 | Sets task sequence variable (TSVariable) to "TRUE" if found. 7 | .PARAMETER URI 8 | URI to web service.This is typically the "http:///ConfigMgrWebService/ConfigMgr.asmx" 9 | .PARAMETER SecretKey 10 | The secret key string set during ConfigMgrWebService installation 11 | .PARAMETER TSVariable 12 | Name of task sequence variable to set/update 13 | .PARAMETER ComputerName 14 | Explicit computer name to use, for testing purposes. 15 | The default is "", and TS variable OSDComputerName is used during task sequence execution 16 | .PARAMETER Delete 17 | Delete computer account in AD and CM DB if found in AD 18 | .EXAMPLE 19 | Test-CMDeviceNameADConflict.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12352342" -TSVariable "ACCTEXISTS" 20 | Sets TS variable "ACCTEXISTS" to "TRUE" if %OSDComputerName% value exists in Active Directory domain 21 | .EXAMPLE 22 | Test-CMDeviceNameADConflict.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12352342" -TSVariable "ACCTEXISTS" -Delete 23 | Sets TS variable "ACCTEXISTS" to "FALSE" if %OSDComputerName% value is found and deleted in Active Directory domain 24 | .EXAMPLE 25 | Test-CMDeviceNameADConflict.ps1 -URI "http://cm01.contoso.local/ConfigMgrWebService/ConfigMgr.asmx" -SecretKey "12352342" -TSVariable "ACCTEXISTS" -ComputerName "WS004" 26 | Sets TS variable "ACCTEXISTS" to "TRUE" if computer "WS004"" exists in Active Directory domain 27 | This is mainly for testing outside of a task sequence environment 28 | .NOTES 29 | Requires the ConfigMgrWebService from SCConfigMgr.com 30 | added RemoveCMDeviceByName step after AD account delete (only if -Delete is used) 31 | #> 32 | [CmdletBinding()] 33 | param ( 34 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $URI, 35 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $SecretKey, 36 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $TSVariable, 37 | [parameter()][string] $ComputerName = "", 38 | [switch] $Delete 39 | ) 40 | try { 41 | $tsenv = New-Object -ComObject Microsoft.SMS.TSEnvironment 42 | $tsActive = $True 43 | Write-Verbose "*** task sequence environment detected" 44 | } 45 | catch { 46 | Write-Verbose "*** not running in a task sequence" 47 | } 48 | try { 49 | $ws = New-WebServiceProxy -Uri $URI -ErrorAction 'stop' 50 | if ([string]::IsNullOrEmpty($ComputerName)) { 51 | if ($tsActive) { 52 | $ComputerName = $($tsenv.Value("OSDComputerName")).Trim() 53 | } 54 | } 55 | if ([string]::IsNullOrEmpty($ComputerName)) { 56 | throw "computer name is null or empty - boo!" 57 | } 58 | Write-Verbose "*** searching for account: $ComputerName" 59 | if (![string]::IsNullOrEmpty(($ws.GetADComputer($SecretKey, $ComputerName)).SamAccountName)) { 60 | if ($tsActive) { $tsenv.Value("$TSVariable") = "TRUE" } 61 | Write-Verbose "*** Set $TSVariable = 'TRUE'" 62 | if ($Delete) { 63 | Write-Verbose "*** deleting $ComputerName`$ from Active Directory" 64 | $ws.RemoveADComputer($SecretKey, "$ComputerName`$") | Out-Null 65 | Write-Verbose "*** deleting $ComputerName from cm database" 66 | $ws.RemoveCMDeviceByName($SecretKey, "$ComputerName") | Out-Null 67 | if ($tsActive) { $tsenv.Value("$TSVariable") = "FALSE" } 68 | Write-Verbose "*** account has been deleted" 69 | } 70 | } 71 | else { 72 | if ($tsActive) { $tsenv.Value("$TSVariable") = "FALSE" } 73 | Write-Verbose "*** account was not found" 74 | } 75 | } 76 | catch { 77 | $_.Exception.Message; Exit 1 78 | } -------------------------------------------------------------------------------- /OSD/Test-NetworkConnectionType.ps1: -------------------------------------------------------------------------------- 1 | # https://deploymentresearch.com/detecting-wired-wireless-and-vpn-connections-using-powershell/ 2 | 3 | #Get Connection Type 4 | $WirelessConnected = $null 5 | $WiredConnected = $null 6 | $VPNConnected = $null 7 | 8 | # Detecting PowerShell version, and call the best cmdlets 9 | if ($PSVersionTable.PSVersion.Major -gt 2) { 10 | # PowerShell 3.0 and above supports Get-CimInstance, and PowerShell 6 and above does not support Get-WmiObject, so using Get-CimInstance. 11 | $WirelessAdapters = Get-CimInstance -Namespace "root\WMI" -Class MSNdis_PhysicalMediumType -Filter 'NdisPhysicalMediumType = 9' 12 | $WiredAdapters = Get-CimInstance -Namespace "root\WMI" -Class MSNdis_PhysicalMediumType -Filter "NdisPhysicalMediumType = 0 and NOT InstanceName like '%pangp%' and NOT InstanceName like '%cisco%' and NOT InstanceName like '%juniper%' and NOT InstanceName like '%vpn%' and NOT InstanceName like 'Hyper-V%' and NOT InstanceName like 'VMware%' and NOT InstanceName like 'VirtualBox Host-Only%'" 13 | $ConnectedAdapters = Get-CimInstance -Class win32_NetworkAdapter -Filter 'NetConnectionStatus = 2' 14 | $VPNAdapters = Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter "Description like '%pangp%' or Description like '%cisco%' or Description like '%juniper%' or Description like '%vpn%'" 15 | } 16 | else { 17 | # Needed this script to work on PowerShell 2.0 (don't ask) 18 | $WirelessAdapters = Get-WmiObject -Namespace "root\WMI" -Class MSNdis_PhysicalMediumType -Filter 'NdisPhysicalMediumType = 9' 19 | $WiredAdapters = Get-WmiObject -Namespace "root\WMI" -Class MSNdis_PhysicalMediumType -Filter "NdisPhysicalMediumType = 0 and NOT InstanceName like '%pangp%' and NOT InstanceName like '%cisco%' and NOT InstanceName like '%juniper%' and NOT InstanceName like '%vpn%' and NOT InstanceName like 'Hyper-V%' and NOT InstanceName like 'VMware%' and NOT InstanceName like 'VirtualBox Host-Only%'" 20 | $ConnectedAdapters = Get-WmiObject -Class win32_NetworkAdapter -Filter 'NetConnectionStatus = 2' 21 | $VPNAdapters = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "Description like '%pangp%' or Description like '%cisco%' or Description like '%juniper%' or Description like '%vpn%'" 22 | } 23 | 24 | 25 | Foreach($Adapter in $ConnectedAdapters) { 26 | If ($WirelessAdapters.InstanceName -contains $Adapter.Name) { 27 | $WirelessConnected = $true 28 | } 29 | } 30 | 31 | Foreach($Adapter in $ConnectedAdapters) { 32 | If ($WiredAdapters.InstanceName -contains $Adapter.Name) { 33 | $WiredConnected = $true 34 | } 35 | } 36 | 37 | Foreach($Adapter in $ConnectedAdapters) { 38 | If ($VPNAdapters.Index -contains $Adapter.DeviceID) { 39 | $VPNConnected = $true 40 | } 41 | } 42 | 43 | If (($WirelessConnected -ne $true) -and ($WiredConnected -eq $true)){$ConnectionType="WIRED"} 44 | If (($WirelessConnected -eq $true) -and ($WiredConnected -eq $true)){$ConnectionType="WIRED AND WIRELESS"} 45 | If (($WirelessConnected -eq $true) -and ($WiredConnected -ne $true)){$ConnectionType="WIRELESS"} 46 | If ($VPNConnected -eq $true){$ConnectionType="VPN"} 47 | 48 | Write-Output "Connection type is: $ConnectionType" 49 | -------------------------------------------------------------------------------- /OSD/desktops-ous.txt: -------------------------------------------------------------------------------- 1 | ENG~OU=Engineering,OU=Desktops,OU=Devices,OU=CORP,DC=contoso,DC=local 2 | EXE~OU=Executive,OU=Desktops,OU=Devices,OU=CORP,DC=contoso,DC=local 3 | HRS~OU=Human Resources,OU=Desktops,OU=Devices,OU=CORP,DC=contoso,DC=local 4 | ITS~OU=IT Services,OU=Desktops,OU=Devices,OU=CORP,DC=contoso,DC=local 5 | FIN~OU=Finance,OU=Desktops,OU=Devices,OU=CORP,DC=contoso,DC=local 6 | MKT~OU=Marketing,OU=Desktops,OU=Devices,OU=CORP,DC=contoso,DC=local 7 | -------------------------------------------------------------------------------- /OSD/laptops-ous.txt: -------------------------------------------------------------------------------- 1 | ENG~OU=Engineering,OU=Laptops,OU=Devices,OU=CORP,DC=contoso,DC=local 2 | EXE~OU=Executive,OU=Laptops,OU=Devices,OU=CORP,DC=contoso,DC=local 3 | HRS~OU=Human Resources,OU=Laptops,OU=Devices,OU=CORP,DC=contoso,DC=local 4 | ITS~OU=IT Services,OU=Laptops,OU=Devices,OU=CORP,DC=contoso,DC=local 5 | FIN~OU=Finance,OU=Laptops,OU=Devices,OU=CORP,DC=contoso,DC=local 6 | MKT~OU=Marketing,OU=Laptops,OU=Devices,OU=CORP,DC=contoso,DC=local 7 | -------------------------------------------------------------------------------- /OSD/locations.txt: -------------------------------------------------------------------------------- 1 | 192.168.0.1=VIRGINIABEACH,VAB 2 | 192.168.1.1=NORFOLK,NOR 3 | 192.168.2.1=CHICAGO,CHI 4 | 192.168.3.1=NEWYORK,NYC 5 | 192.168.4.1=SEATTLE,SEA 6 | 192.168.5.1=MIAMI,MIA 7 | 192.168.6.1=ATLANTA,ATL 8 | 192.168.7.1=CHARLOTTE,CLT 9 | 192.168.8.1=AUSTIN,ATX 10 | -------------------------------------------------------------------------------- /OSD/osd-locations.csv: -------------------------------------------------------------------------------- 1 | IPGateway,Loc,LocationName 2 | 192.168.0.1,NOR,Norfolk 3 | 192.168.1.1,NYC,New York City 4 | 192.168.2.1,CHI,Chicago 5 | 192.168.3.1,LAX,Los Angeles 6 | -------------------------------------------------------------------------------- /OSD/oulocations.txt: -------------------------------------------------------------------------------- 1 | 192.168.1.1:VAB:OU=VirginiaBeach,OU=CORP,DC=contoso,DC=local 2 | 192.168.2.1:VAB:OU=VirginiaBeach,OU=CORP,DC=contoso,DC=local 3 | 192.168.3.1:NOR:OU=Norfolk,OU=CORP,DC=contoso,DC=local 4 | 192.168.4.1:CHI:OU=Chicago,OU=CORP,DC=contoso,DC=local 5 | 192.168.5.1:NYC:OU=NewYork,OU=CORP,DC=contoso,DC=local 6 | 192.168.6.1:DEN:OU=Denver,OU=CORP,DC=contoso,DC=local 7 | 192.168.7.1:SFO:OU=SanFransisco,OU=CORP,DC=contoso,DC=local 8 | 192.168.8.1:MIA:OU=Miami,OU=CORP,DC=contoso,DC=local -------------------------------------------------------------------------------- /OSD/ps-delay-120sec.cmd: -------------------------------------------------------------------------------- 1 | powershell.exe -ExecutionPolicy Bypass -NoProfile -Command "& { Start-Sleep -Seconds 120 }" 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SCCM 2 | 3 | ## Description 4 | 5 | This repo contains scripts which are a mix of custom (mine) and publicly-available works of others. 6 | Thank you for your support! And remember to vote early and vote often. :) 7 | 8 | ## Disclaimers 9 | 10 | * No warranty or guarantee is provided, explicit or implied, for any purpose, use, or adaptation, whether direct or derived, for any code examples or sample data provided on this site. 11 | * USE AT YOUR OWN RISK 12 | * User assumes ANY AND ALL RISK and LIABILITY for any and all usage of examples provided herein. Author assumes no liability for any consequences of using these examples for any purpose whatsoever. 13 | * I make every possible, conceivable, imaginable, effort to indicate the author of each script wherever humanly possible, however, it is possible with my limited cranial capacity, that I may have overlooked one or more scripts. 14 | * Please let me know if you see something which belongs to you, the URL where it originates, and I will be sure to update my copy to provide clear, absolute, undeniable, irrefutable, inescapable, declaration of the correct author and URL where the original resides. 15 | -------------------------------------------------------------------------------- /Run-CmCustomQuery.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3 2 | <# 3 | .DESCRIPTION 4 | Sneak in and read data from ConfigMgr SQL database 5 | .PARAMETER ServerName 6 | SQL Server Hostname (FQDN) 7 | .PARAMETER SiteCode 8 | ConfigMgr Site Code 9 | .PARAMETER QPath 10 | Path to .sql files (default is .\queries) 11 | .PARAMETER Output 12 | List: Grid, Csv, Pipeline 13 | .EXAMPLE 14 | .\Run-CmCustomQuery.ps1 15 | .EXAMPLE 16 | .\Run-CmCustomQuery.ps1 -ServerName "cm01.fabrikam.local" -SiteCode "PS1" 17 | .EXAMPLE 18 | .\Run-CmCustomQuery.ps1 -Output Csv 19 | .EXAMPLE 20 | .\Run-CmCustomQuery.ps1 -Output Pipeline | ?{$_.Installs -gt 50} 21 | .NOTES 22 | 0.1.0 - DS - Initial release 23 | 0.1.1 - DS - Documentation, Gridview title enhancement 24 | 0.1.2 - DS - Display output path for CSV option at completion 25 | #> 26 | 27 | [CmdletBinding()] 28 | param ( 29 | [parameter(Mandatory=$False, HelpMessage="ConfigMgr DB Server Name")] 30 | [ValidateNotNullOrEmpty()] 31 | [string] $ServerName = "hcidalas37.hci.pvt", 32 | [parameter(Mandatory=$False, HelpMessage="ConfigMgr Site Code")] 33 | [ValidateNotNullOrEmpty()] 34 | [string] $SiteCode = "HHQ", 35 | [parameter(Mandatory=$False, HelpMessage="Path to query files")] 36 | [ValidateNotNullOrEmpty()] 37 | [string] $QPath = ".\queries", 38 | [parameter(Mandatory=$False)] 39 | [ValidateSet('Grid','Csv','Pipeline')] 40 | [string] $Output = 'Grid' 41 | ) 42 | $DatabaseName = "CM_$SiteCode" 43 | 44 | $qfiles = Get-ChildItem -Path $QPath -Filter "*.sql" | Sort-Object Name 45 | Write-Verbose "$($qfiles.count) files were found" 46 | if ($qfiles.count -lt 1) { 47 | Write-Warning "$qpath contains no .sql files" 48 | break 49 | } 50 | 51 | Write-Verbose "display list in gridview for user to select" 52 | 53 | $qfile = $qfiles | Select -ExpandProperty Name | 54 | Out-GridView -Title "Select Query to Run" -OutputMode Single 55 | 56 | if (![string]::IsNullOrEmpty($qfile)) { 57 | Write-Verbose "selected: $qfile" 58 | $qpath = Join-Path -Path $qpath -ChildPath $qfile 59 | Write-Verbose "filepath: $qpath" 60 | $qtext = Get-Content -Path $qpath 61 | if (![string]::IsNullOrEmpty($qtext)) { 62 | $QueryTimeout = 120 63 | $ConnectionTimeout = 30 64 | Write-Verbose "QUERY: $qtext" 65 | #Action of connecting to the Database and executing the query and returning results if there were any. 66 | $conn = New-Object System.Data.SqlClient.SQLConnection 67 | $ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerName,$DatabaseName,$ConnectionTimeout 68 | $conn.ConnectionString = $ConnectionString 69 | $conn.Open() 70 | $cmd = New-Object System.Data.SqlClient.SqlCommand($qtext,$conn) 71 | $cmd.CommandTimeout = $QueryTimeout 72 | $ds = New-Object System.Data.DataSet 73 | $da = New-Object System.Data.SqlClient.SqlDataAdapter($cmd) 74 | [void]$da.Fill($ds) 75 | $conn.Close() 76 | $rowcount = $($ds.Tables).Rows.Count 77 | if ($rowcount -gt 0) { 78 | Write-Host "$rowcount rows returned" -ForegroundColor Green 79 | switch ($Output) { 80 | 'Grid' { 81 | $($ds.Tables).Rows | Out-GridView -Title "Query Results: $($qfile -replace '.sql','')" 82 | break 83 | } 84 | 'Csv' { 85 | $csvfile = "$($qfile -replace '.sql','.csv')" 86 | $($ds.Tables).Rows | Export-Csv -NoTypeInformation -Path $csvfile 87 | Write-Host "exported to: $csvfile" -ForegroundColor Green 88 | break 89 | } 90 | default { 91 | $($ds.Tables).Rows 92 | } 93 | } # switch 94 | } 95 | else { 96 | Write-Host "No rows were returned" -ForegroundColor Magenta 97 | } 98 | } 99 | else { 100 | Write-Warning "$qfile is empty" 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /UD/New-CMWebService.ps1: -------------------------------------------------------------------------------- 1 | # Example --> Invoke-RestMethod http://localhost:10001/api/cmdevices 2 | 3 | [CmdletBinding()] 4 | param ( 5 | [parameter()][string] $SiteCode = "P01", 6 | [parameter()][int] $Port = 10001 7 | ) 8 | try { 9 | if (!(Get-Module UniversalDashboard.Community)) { 10 | Install-Module UniversalDashboard.Community 11 | } 12 | Import-Module UniversalDashboard.Community 13 | } 14 | catch { 15 | Write-Error $_.Exception.Message 16 | Exit 17 | } 18 | 19 | try { 20 | $devices = Get-WmiObject -Class "SMS_R_System" -Namespace "root\SMS\Site_$SiteCode" | 21 | Select ResourceID,Name,Client,ClientVersion,ADSiteName,DistinguishedName,MACAddresses,IPAddresses,LastLogonTimestamp,OperatingSystemNameandVersion,Build 22 | $Cache:CMDevices = @( $devices ) 23 | $Endpoints = @() 24 | 25 | $Endpoints += New-UDEndpoint -Url 'cmdevices' -Endpoint { 26 | $Cache:CMDevices | ConvertTo-Json 27 | } 28 | Start-UDRestApi -Endpoint $Endpoints -Port $Port -AutoReload -Name "cmdevices" 29 | } 30 | catch { 31 | Write-Error $_.Exception.Message 32 | } 33 | -------------------------------------------------------------------------------- /WQL/clients_by_ou.wql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT * 2 | FROM SMS_R_System AS Sys 3 | WHERE 4 | Sys.SystemOUName = 'Contoso.Domain.local/OUName' 5 | -------------------------------------------------------------------------------- /WQL/clients_laptops.wql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT * 2 | FROM SMS_R_System AS Sys 3 | INNER JOIN SMS_G_System_System_Enclosure AS Case ON 4 | Case.ResourceId = Sys.ResourceId 5 | WHERE 6 | Case.ChassisTypes IN ('11', '10', '9', '8') 7 | -------------------------------------------------------------------------------- /_CM_TEMPLATE.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | 4 | 5 | .DESCRIPTION 6 | 7 | 8 | .PARAMETER SiteServer 9 | Site server name with SMS Provider installed. 10 | 11 | .PARAMETER ShowProgress 12 | Show a progressbar displaying the current operation. 13 | 14 | .EXAMPLE 15 | 16 | 17 | .NOTES 18 | FileName: FileName.ps1 19 | Author: Nickolaj Andersen 20 | Contact: @NickolajA 21 | Created: 2016-03-22 22 | Updated: 2016-03-22 23 | Version: 1.0.0 24 | #> 25 | [CmdletBinding(SupportsShouldProcess=$true)] 26 | param( 27 | [parameter(Mandatory=$true, HelpMessage="Site server where the SMS Provider is installed.")] 28 | [ValidateNotNullOrEmpty()] 29 | [ValidateScript({Test-Connection -ComputerName $_ -Count 1 -Quiet})] 30 | [string]$SiteServer, 31 | 32 | [parameter(Mandatory=$false, HelpMessage="Show a progressbar displaying the current operation.")] 33 | [switch]$ShowProgress 34 | ) 35 | Begin { 36 | # Determine SiteCode from WMI 37 | try { 38 | Write-Verbose -Message "Determining Site Code for Site server: '$($SiteServer)'" 39 | $SiteCodeObjects = Get-WmiObject -Namespace "root\SMS" -Class SMS_ProviderLocation -ComputerName $SiteServer -ErrorAction Stop 40 | foreach ($SiteCodeObject in $SiteCodeObjects) { 41 | if ($SiteCodeObject.ProviderForLocalSite -eq $true) { 42 | $SiteCode = $SiteCodeObject.SiteCode 43 | Write-Verbose -Message "Site Code: $($SiteCode)" 44 | } 45 | } 46 | } 47 | catch [System.UnauthorizedAccessException] { 48 | Write-Warning -Message "Access denied" ; break 49 | } 50 | catch [System.Exception] { 51 | Write-Warning -Message "Unable to determine Site Code" ; break 52 | } 53 | 54 | # Load assemblies 55 | try { 56 | Add-Type -Path (Join-Path -Path (Get-Item $env:SMS_ADMIN_UI_PATH).Parent.FullName -ChildPath "Microsoft.ConfigurationManagement.ApplicationManagement.dll") -ErrorAction Stop 57 | Add-Type -Path (Join-Path -Path (Get-Item $env:SMS_ADMIN_UI_PATH).Parent.FullName -ChildPath "Microsoft.ConfigurationManagement.ApplicationManagement.Extender.dll") -ErrorAction Stop 58 | Add-Type -Path (Join-Path -Path (Get-Item $env:SMS_ADMIN_UI_PATH).Parent.FullName -ChildPath "Microsoft.ConfigurationManagement.ApplicationManagement.MsiInstaller.dll") -ErrorAction Stop 59 | } 60 | catch [System.UnauthorizedAccessException] { 61 | Write-Warning -Message "Access denied" ; break 62 | } 63 | catch [System.Exception] { 64 | Write-Warning -Message $_.Exception.Message ; break 65 | } 66 | 67 | # Load ConfigMgr module 68 | try { 69 | $SiteDrive = $SiteCode + ":" 70 | Import-Module -Name ConfigurationManager -ErrorAction Stop -Verbose:$false 71 | } 72 | catch [System.UnauthorizedAccessException] { 73 | Write-Warning -Message "Access denied" ; break 74 | } 75 | catch [System.Exception] { 76 | try { 77 | Import-Module -Name (Join-Path -Path (($env:SMS_ADMIN_UI_PATH).Substring(0,$env:SMS_ADMIN_UI_PATH.Length-5)) -ChildPath "\ConfigurationManager.psd1") -Force -ErrorAction Stop -Verbose:$false 78 | if ((Get-PSDrive -Name $SiteCode -ErrorAction SilentlyContinue | Measure-Object).Count -ne 1) { 79 | New-PSDrive -Name $SiteCode -PSProvider "AdminUI.PS.Provider\CMSite" -Root $SiteServer -ErrorAction Stop -Verbose:$false | Out-Null 80 | } 81 | } 82 | catch [System.UnauthorizedAccessException] { 83 | Write-Warning -Message "Access denied" ; break 84 | } 85 | catch [System.Exception] { 86 | Write-Warning -Message "$($_.Exception.Message). Line: $($_.InvocationInfo.ScriptLineNumber)" ; break 87 | } 88 | } 89 | 90 | # Determine and set location to the CMSite drive 91 | $CurrentLocation = $PSScriptRoot 92 | Set-Location -Path $SiteDrive -ErrorAction Stop -Verbose:$false 93 | 94 | # Disable Fast parameter usage check for Lazy properties 95 | $CMPSSuppressFastNotUsedCheck = $true 96 | } 97 | Process { 98 | if ($PSBoundParameters["ShowProgress"]) { 99 | $ProgressCount = 0 100 | } 101 | # Main code part goes here 102 | } 103 | End { 104 | Set-Location -Path $CurrentLocation 105 | } -------------------------------------------------------------------------------- /cmtools/Clear-ScomAgentCache.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Clear SCOM agent cache on remote computers 4 | .DESCRIPTION 5 | Clear SCOM agent cache on remote computers 6 | .PARAMETER InputFile 7 | Text file containing names of remote computers to process 8 | One computer name on each line, avoid empty lines 9 | .EXAMPLE 10 | .\Clear-ScomAgentCache.ps1 -InputFile ".\computernames.txt" 11 | .NOTES 12 | Adapted from http://www.ms-opsmgr.eu/?tag=maintenancemode-scom-scom2012-powershell 13 | by David Stein / 1910.25 14 | #> 15 | [CmdletBinding()] 16 | param( 17 | [parameter(Mandatory,Position=0)][string]$InputFile 18 | ) 19 | $ErrorActionPreference = 'SilentlyContinue' 20 | 21 | if (!(Get-Module OperationsManager -ListAvailable)) { 22 | Write-Warning "OperationsManager module is not installed. Aborting." 23 | exit 24 | } 25 | try { 26 | $computers = Get-Content $InputFile 27 | if ($null -eq $computers) { 28 | Write-Warning "no computer names were imported" 29 | break 30 | } 31 | foreach ($computer in $computers) { 32 | $RemoteComputer = Get-SCOMClassInstance -Name $computer 33 | if ($null -ne $RemoteComputer) { 34 | $CurrentimePlus10Minutes = ((Get-Date).AddMinutes(10)) 35 | Write-Verbose "$computer : Setting Maintenance mode for remote Computer" 36 | Start-SCOMMaintenanceMode -Instance $RemoteComputer -EndTime $CurrentimePlus10Minutes -Comment "Flushing System Center Operations Manager Agent Cache" 37 | Write-Verbose "$computer : is in Maintenance mode for 10 Minutes" 38 | 39 | Write-Verbose "$computer : Stopping service: HealthService" 40 | Invoke-Command -ComputerName $RemoteComputer {Net Stop "HealthService"} 41 | 42 | Write-Verbose "$computer : clearing agent cache" 43 | Invoke-Command -ComputerName $RemoteComputer {Get-ChildItem -Recurse -Path "C:\Program Files\System Center Operations Manager\Agent\Health Service State" | Remove-Item -Force -Recurse} 44 | Write-Verbose "$computer : The System Center Agent Cache is cleared." 45 | 46 | Write-Verbose "$computer : Restarting service: HealthService" 47 | Invoke-Command -ComputerName $RemoteComputer {Net Start "HealthService"} 48 | Write-Host "$computer : Cache has been cleared" 49 | } 50 | else { 51 | Write-Host "$computer : Computer is offline or inaccessible" 52 | } 53 | } 54 | } 55 | catch { 56 | Write-Error $_.Exception.Message 57 | } 58 | -------------------------------------------------------------------------------- /collections/Add-CMDeviceToCollection.ps1: -------------------------------------------------------------------------------- 1 | #requires -Module ConfigurationManager 2 | 3 | [CmdletBinding(SupportsShouldProcess=$True)] 4 | param ( 5 | [parameter(Mandatory=$True, HelpMessage="Computer Name")] 6 | [ValidateNotNullOrEmpty()] 7 | [string] $ComputerName, 8 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr Collection ID")] 9 | [ValidateNotNullOrEmpty()] 10 | [string] $CollectionID, 11 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr MP")] 12 | [ValidateNotNullOrEmpty()] 13 | [string] $ServerName, 14 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr Site Code")] 15 | [ValidateNotNullOrEmpty()] 16 | [string] $SiteCode 17 | ) 18 | 19 | $oldLoc = Get-Location 20 | Write-Verbose "current location is $oldLoc" 21 | Write-Verbose "setting location to $SiteCode`:" 22 | Set-Location "$($SiteCode):" 23 | 24 | try { 25 | $ResourceID = Get-CMDevice -Name $ComputerName | Select -ExpandProperty ResourceID 26 | Write-Verbose "resourceID = $ResourceID" 27 | try { 28 | Add-CMDeviceCollectionDirectMembershipRule -CollectionId $CollectionID -ResourceId $ResourceID -ErrorAction SilentlyContinue 29 | $result = 0 30 | } 31 | catch { 32 | $result = $Error[0].Errors[0].ErrorId 33 | } 34 | } 35 | catch { 36 | Write-Warning $Error[0].Exception.Message 37 | $result = 2 38 | } 39 | finally { 40 | Write-Verbose "restoring previous location" 41 | Set-Location $oldLoc 42 | } 43 | Write-Verbose "process completed with $result" 44 | Write-Output $result 45 | -------------------------------------------------------------------------------- /collections/Compare-ListToCmCollection.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBindint() 2 | param ( 3 | [parameter(Mandatory=$False, HelpMessage="File containing computer names")] 4 | [string] $ListFile = "", 5 | [parameter(Mandatory=$False, HelpMessage="ConfigMgr CollectionID")] 6 | [string] $CollectionID = "", 7 | [parameter(Mandatory=$False, HelpMessage="Path to computer list files")] 8 | [ValidateNotNullOrEmpty()] 9 | [string] $InputFilesPath = ".\lists", 10 | [parameter(Mandatory=$False, HelpMessge="ConfigMgr SQL Server host name")] 11 | [ValidateNotNullOrEmpty()] 12 | [string] $ServerName = "cm01.contoso.local", 13 | [parameter(Mandatory=$False, HelpMessage="ConfigMgr site code")] 14 | [ValidateNotNullOrEmpty()] 15 | [string] $SiteCode = "P01", 16 | [parameter(Mandatory=$False, HelpMessage="Show total relative counts only")] 17 | [switch] $Summary, 18 | [parameter(Mandatory=$False, HelpMessage="Show extended AD and ConfigMgr data for each device")] 19 | [switch] $Detailed 20 | ) 21 | if ([string]::IsNullOrEmpty($ListFile)) { 22 | $ListFile = Get-ChildItem -Path $InputFilesPath -Filter "*.txt" | Out-GridView -Title "Select File to Process" -OutputMode Single 23 | if (!$ListFile) { break } 24 | Write-Host "$ListFile" -ForegroundColor Cyan 25 | $filepath = $ListFile.FullName 26 | $filename = $ListFile.BaseName 27 | } 28 | else { 29 | Write-Host "reading list file: $ListFile" -ForegroundColor Cyan 30 | $x = Get-Item -Path $ListFile 31 | $filepath = $x.FullName 32 | $filename = $x.BaseName 33 | } 34 | $fileMembers = Get-Content -Path $filepath 35 | 36 | if ([string]::IsNullOrEmpty($CollectionID)) { 37 | $collData = .\tools\Get-CmCollectionMember.ps1 -ServerName $ServerName -SiteCode $SiteCode -Choose 38 | } 39 | else { 40 | $collData = .\tools\Get-CmCollectionMember.ps1 -CollectionID $CollectionID -ServerName $ServerName -SiteCode $SiteCode 41 | } 42 | 43 | $collmembers = $collData | Select -ExpandProperty ComputerName 44 | if ($Summary) { 45 | Write-Host "collection members: $($collmembers.Count)" 46 | Write-Host "file list members: $($fileMembers.Count)" 47 | } 48 | else { 49 | $result = @() 50 | $rownum = 1 51 | foreach ($fm in $fileMembers) { 52 | if ($collmembers -contains $fm) { 53 | $ismember = $True 54 | } 55 | else { 56 | $ismember = $False 57 | } 58 | if ($Detailed) { 59 | $adlogin = .\tools\Get-ADsComputers.ps1 -ComputerName $fm | Select -ExpandProperty LastLogon 60 | $cmdata = .\tools\Get-CMDeviceInfo.ps1 -ServerName $ServerName -SiteCode $SiteCode -ComputerNames $fm 61 | $props1 = [ordered]@{ 62 | ComputerName = $fm 63 | RowID = $rownum 64 | FileMember = $True 65 | CollMember = $ismember 66 | ADLastLogin = $adlogin 67 | CMClient = $cmdata.ClientVersion 68 | CMHwScan = $cmdata.LastHwScan 69 | } 70 | } 71 | else { 72 | $props1 = [ordered]@{ 73 | ComputerName = $fm 74 | RowID = $rownum 75 | FileMember = $True 76 | CollMember = $ismember 77 | } 78 | } 79 | $result += $(New-Object PSObject -Property $props1) 80 | $rownum++ 81 | } 82 | foreach ($cm in $collmembers) { 83 | if ($Detailed) { 84 | $adlogin = .\tools\Get-ADsComputers.ps1 -ComputerName $cm | Select -ExpandProperty LastLogon 85 | $cmdata = .\tools\Get-CMDeviceInfo.ps1 -ServerName $ServerName -SiteCode $SiteCode -ComputerNames $cm 86 | if ($fileMembers -notcontains $cm) { 87 | $props2 = [ordered]@{ 88 | ComputerName = $cm 89 | RowID = $rownum 90 | FileMember = $False 91 | CollMember = $True 92 | ADLastLogin = $adlogin 93 | CMClient = $cmdata.ClientVersion 94 | CMHwScan = $cmdata.LastHwScan 95 | } 96 | $result += $(New-Object PSObject -Property $props2) 97 | } 98 | } 99 | else { 100 | if ($fileMembers -notcontains $cm) { 101 | $props2 = [ordered]@{ 102 | ComputerName = $cm 103 | RowID = $rownum 104 | FileMember = $False 105 | CollMember = $True 106 | } 107 | $result += $(New-Object PSObject -Property $props2) 108 | } 109 | } 110 | $rownum++ 111 | } 112 | $result 113 | } 114 | -------------------------------------------------------------------------------- /collections/Export-CmCollectionMembers.ps1: -------------------------------------------------------------------------------- 1 | #requires -Modules dbatools 2 | #requires -Version 5.1 3 | <# 4 | .SYNOPSIS 5 | Export CSV file of Collection Members 6 | .DESCRIPTION 7 | Export CSV file of Collection Members 8 | .PARAMETER SiteServer 9 | Name of ConfigMgr site database host 10 | .PARAMETER SiteCode 11 | 3 character ConfigMgr site code 12 | .PARAMETER CollectionType 13 | 'Device' or 'User' (default is 'Device') 14 | User option is not yet ready 15 | .EXAMPLE 16 | Export-CmCollectionMembers.ps1 -SiteServer "CM01" -SiteCode "P01" 17 | Exports all members of selected device collection to file 18 | Filename is COLLECTIONID-COLLECTIONNAME-Members.csv in the current working folder 19 | .EXAMPLE 20 | Export-CmCollectionMembers.ps1 -SiteServer "CM01" -SiteCode "P01" -CollectionType 'User' 21 | Exports all members of selected user collection to file 22 | Filename is COLLECTIONID-COLLECTIONNAME-Members.csv in the current working folder 23 | .NOTES 24 | 1.0.0 - DS - Initial release 25 | 26 | PROVIDED "AS-IS" WITHOUT WARRANTY OR GUARANTEE OF ANY KIND FOR ANY PURPOSE 27 | USE AT YOUR OWN RISK. 28 | #> 29 | [CmdletBinding()] 30 | param ( 31 | [parameter(Mandatory)][ValidateNotNullOrEmpty()][string] $SiteServer, 32 | [parameter(Mandatory)][ValidateLength(3,3)][string] $SiteCode, 33 | [parameter()][ValidateSet('Device')][string] $CollectionType = "Device" 34 | ) 35 | try { 36 | if ($CollectionType -eq 'Device') {$Ctype = 2} else {$Ctype = 1} 37 | $qs = "select Name,CollectionID,MemberCount as Members,Comment from v_collection where CollectionType=$Ctype order by Name" 38 | $colls = Invoke-DbaQuery -SqlInstance $SiteServer -Database "CM_$SiteCode" -Query $qs 39 | Write-Verbose "$($colls.Count) collections returned from query" 40 | $coll = $colls | Out-GridView -Title "Select Collection to Export" -OutputMode Single 41 | if ($coll) { 42 | $cid = $coll.CollectionID 43 | $cn = $coll.Name 44 | if ($coll.Members -eq 0) { 45 | Write-Warning "collection has no members to export" 46 | } 47 | else { 48 | $qm = "SELECT DISTINCT ccm.Name, ccm.IsClient AS Client, 49 | sys.User_Name0 AS UserName, sys.Operating_System_Name_and0 AS OSName, 50 | cs.Model0 AS Model, sys.AD_Site_Name0 AS ADSiteName 51 | FROM v_ClientCollectionMembers AS ccm INNER JOIN 52 | v_R_System AS sys ON ccm.ResourceID = sys.ResourceID INNER JOIN 53 | v_GS_COMPUTER_SYSTEM AS cs ON ccm.ResourceID = cs.ResourceID 54 | WHERE ccm.CollectionID = '$cid' ORDER BY Name" 55 | Write-Verbose "query: $qm" 56 | $csvFile = Join-Path $PSScriptRoot "$cid`-$cn`-Members.csv" 57 | $mbrs = Invoke-DbaQuery -SqlInstance $SiteServer -Database "CM_$SiteCode" -Query $qm | Foreach-Object { 58 | [pscustomobject]@{ 59 | Name = [string]$_.Name 60 | UserName = [string]$_.UserName 61 | OSName = [string]$_.OSName 62 | Model = [string]$_.Model 63 | ADSiteName = [string]$_.ADSiteName 64 | } 65 | } 66 | Write-Verbose "$($mbrs.Count) members returned from query" 67 | $mbrs | Export-Csv -Path $csvFile -NoTypeInformation -Force 68 | Write-Host "exported to $csvFile" -ForegroundColor Cyan 69 | } 70 | } 71 | } 72 | catch { 73 | Write-Error $Error[0].Exception.Message 74 | } -------------------------------------------------------------------------------- /collections/Get-CMCollectionID.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [parameter(Mandatory=$False, HelpMessage="Name of Collection")] 4 | [string] $CollectionName = "", 5 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr SQL Server Hostname")] 6 | [ValidateNotNullOrEmpty()] 7 | [string] $ServerName, 8 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr Site Code")] 9 | [ValidateNotNullOrEmpty()] 10 | [string] $SiteCode, 11 | [parameter(Mandatory=$False, HelpMessage="Type of Collection")] 12 | [ValidateSet('Device','User')] 13 | [string] $CollectionType = 'Device', 14 | [parameter(Mandatory=$False, HelpMessage="Wildcard filter on Collection Names list")] 15 | [switch] $Like 16 | ) 17 | $DatabaseName = "CM_$SiteCode" 18 | $QueryTimeout = 120 19 | $ConnectionTimeout = 30 20 | $conn = New-Object System.Data.SqlClient.SQLConnection 21 | $ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerName,$DatabaseName,$ConnectionTimeout 22 | $conn.ConnectionString = $ConnectionString 23 | try { 24 | $conn.Open() 25 | Write-Verbose "connection opened successfully" 26 | } 27 | catch { 28 | Write-Error $_.Exception.Message 29 | break 30 | } 31 | $query = "SELECT DISTINCT CollectionID, Name, MemberCount FROM dbo.v_Collection" 32 | 33 | if ([string]::IsNullOrEmpty($CollectionName)) { 34 | $query += " ORDER BY Name" 35 | } 36 | else { 37 | if ($Like) { 38 | $query += " WHERE Name LIKE '$CollectionName`%'" 39 | } 40 | else { 41 | $query += " WHERE Name='$CollectionName'" 42 | } 43 | } 44 | Write-Verbose "query: $query" 45 | $cmd = New-Object System.Data.SqlClient.SqlCommand($query,$conn) 46 | $cmd.CommandTimeout = $QueryTimeout 47 | $ds = New-Object System.Data.DataSet 48 | $da = New-Object System.Data.SqlClient.SqlDataAdapter($cmd) 49 | [void]$da.Fill($ds) 50 | $conn.Close() 51 | 52 | $rowcount = $($ds.Tables).Rows.Count 53 | Write-Verbose "$rowcount rows returned" 54 | 55 | if ($rowcount -gt 0) { 56 | Write-Host "$rowcount collections returned" -ForegroundColor Cyan 57 | if ([string]::IsNullOrEmpty($CollectionName)) { 58 | $x = $($ds.Tables).Rows | Out-GridView -Title "Select Collection" -OutputMode Single 59 | if ($x) { 60 | Write-Verbose "name: $($x | Select -ExpandProperty Name)" 61 | Write-Output $($x | Select -ExpandProperty CollectionID) 62 | } 63 | else { 64 | Write-Warning "No selection made" 65 | break 66 | } 67 | } 68 | else { 69 | if (!$Like) { 70 | $x = $($ds.Tables).Rows[0] 71 | Write-Verbose "name: $CollectionName" 72 | Write-Output $($x | Select -ExpandProperty CollectionID) 73 | } 74 | else { 75 | $x = $($ds.Tables).Rows | Out-GridView -Title "Select Collection" -OutputMode Single 76 | if ($x) { 77 | Write-Verbose "name: $($x | Select -ExpandProperty Name)" 78 | Write-Output $($x | Select -ExpandProperty CollectionID) 79 | } 80 | else { 81 | Write-Warning "No selection made" 82 | break 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /collections/Get-CMCollectionMemberFileMember.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [parameter(Mandatory=$True)] 4 | [ValidateNotNullOrEmpty()] 5 | [string] $CollectionID, 6 | [parameter(Mandatory=$True)] 7 | [ValidateNotNullOrEmpty()] 8 | [string] $InputFile, 9 | [parameter(Mandatory=$False)] 10 | [switch] $DeepInspect, 11 | [parameter(Mandatory=$False)] 12 | [switch] $ShowReverse 13 | ) 14 | $members = .\Get-CmCollectionMembers.ps1 -CollectionID $CollectionID 15 | $memberNames = $members | Select -ExpandProperty ComputerName 16 | $computerlist = Get-Content -Path $InputFile 17 | 18 | foreach ($cn in $computerlist) { 19 | if ($DeepInspect) { 20 | try { 21 | Write-Verbose "connecting to: $cn (deep)" 22 | $x = Test-NetConnection -ComputerName $cn -WarningAction SilentlyContinue 23 | if ($x.PingSucceeded) { 24 | $stat = "ONLINE" 25 | } 26 | elseif ($x.RemoteAddress) { 27 | $stat = "OFFLINE" 28 | } 29 | else { 30 | $stat = "NO DNS" 31 | } 32 | } 33 | catch { 34 | $stat = "ERROR" 35 | } 36 | } 37 | else { 38 | Write-Verbose "connecting to: $cn" 39 | if (Test-NetConnection -ComputerName $cn -InformationLevel Quiet) { 40 | $stat = "ONLINE" 41 | } 42 | else { 43 | $stat = "OFFLINE" 44 | } 45 | } 46 | if ($memberNames -notcontains $cn) { 47 | $ismember = $False 48 | Write-Verbose "$cn is not in collection" 49 | } 50 | else { 51 | $ismember = $True 52 | Write-Verbose "$cn is ONLINE" 53 | } 54 | $data = [ordered]@{ 55 | Computer = $cn 56 | IsOnline = $stat 57 | IsMember = $ismember 58 | } 59 | New-Object PSObject -Property $data 60 | } # foreach 61 | 62 | if ($ShowReverse) { 63 | foreach ($m in $members) { 64 | if ($computerlist -notcontains $m) { 65 | Write-Host "$m is not in file" 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /collections/Get-CMCollectionsList.ps1: -------------------------------------------------------------------------------- 1 | function Get-CmCollectionsList { 2 | [CmdletBinding()] 3 | param ( 4 | [parameter(Mandatory=$True)] 5 | [string] $CmDbHost, 6 | [parameter(Mandatory=$True)] 7 | [string] $CmSiteCode, 8 | [parameter(Mandatory=$False)] 9 | [ValidateSet('direct','query','all')] 10 | [string] $MembershipType = 'all' 11 | ) 12 | switch ($MembershipType) { 13 | 'all' { 14 | $query = 'SELECT DISTINCT dbo.v_Collection.CollectionID, dbo.v_Collection.Name, dbo.v_Collection.CollectionType 15 | FROM dbo.v_Collection ORDER BY dbo.v_Collection.Name' 16 | break; 17 | } 18 | 'query' { 19 | $query = 'SELECT DISTINCT dbo.v_CollectionRuleQuery.CollectionID, dbo.v_Collection.Name, dbo.v_Collection.CollectionType 20 | FROM dbo.v_CollectionRuleQuery INNER JOIN dbo.v_Collection ON 21 | dbo.v_CollectionRuleQuery.CollectionID = dbo.v_Collection.CollectionID 22 | ORDER BY dbo.v_Collection.Name' 23 | break; 24 | } 25 | 'direct' { 26 | $query = 'SELECT DISTINCT 27 | dbo.v_Collection.CollectionID, dbo.v_Collection.Name, dbo.v_Collection.CollectionType 28 | FROM dbo.v_Collection WHERE CollectionID NOT IN ( 29 | SELECT DISTINCT CollectionID from dbo.v_CollectionRuleQuery) 30 | ORDER BY dbo.v_Collection.Name' 31 | break; 32 | } 33 | } 34 | Write-Verbose "query: $query" 35 | try { 36 | $connection = New-Object -ComObject "ADODB.Connection" 37 | $connString = "Data Source=$CmDBHost;Initial Catalog=CM_$CmSiteCode;Integrated Security=SSPI;Provider=SQLOLEDB" 38 | $connection.Open($connString); 39 | $IsOpen = $True 40 | Write-Verbose "connection is opened" 41 | $rs = New-Object -ComObject "ADODB.RecordSet" 42 | $rs.Open($query, $connection) 43 | Write-Verbose "recordset opened" 44 | while (!$rs.EOF) { 45 | Write-Verbose "reading recordset row..." 46 | $props = [ordered]@{ 47 | CollectionID = $rs.Fields("CollectionID").value | Out-String 48 | Name = $rs.Fields("Name").value | Out-String 49 | Type = $rs.Fields("CollectionType").value | Out-String 50 | } 51 | New-Object PSObject -Property $props 52 | $rs.MoveNext() 53 | } 54 | Write-Verbose "closing recordset" 55 | $rs.Close 56 | } 57 | catch { 58 | if ($IsOpen -eq $True) { [void]$connection.Close() } 59 | throw "Error: $($Error[0].Exception.Message)" 60 | } 61 | finally { 62 | Write-Verbose "closing connection" 63 | if ($IsOpen -eq $True) { [void]$connection.Close() } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /collections/Get-CMDeviceCollections.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .DESCRIPTION 3 | Query collection memberships for a specific device 4 | .PARAMETER ComputerName 5 | Name of the device 6 | .PARAMETER ServerName 7 | ConfigMgr SQL Server host name (FQDN) 8 | .PARAMETER SiteCode 9 | ConfigMgr Site Code 10 | .EXAMPLE 11 | $colls = .\Get-CmDeviceCollections.ps1 -ComputerName "DT12345" -ServerName "cm01.contoso.local" -SiteCode "P01" 12 | .NOTES 13 | 1.0.0 - DS - initial release 14 | 1.0.1 - DS - general cleanup and documentation 15 | #> 16 | 17 | [CmdletBinding()] 18 | param ( 19 | [parameter(Mandatory=$True, HelpMessage="Computer Name")] 20 | [ValidateNotNullOrEmpty()] 21 | [string] $ComputerName, 22 | [parameter(Mandatory=$True, HelpMessage="Site Database Server Name")] 23 | [ValidateNotNullOrEmpty()] 24 | [string] $ServerName, 25 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr Site Code")] 26 | [ValidateNotNullOrEmpty()] 27 | [string] $SiteCode 28 | ) 29 | $qtext = @" 30 | SELECT DISTINCT 31 | dbo.v_ClientCollectionMembers.CollectionID, 32 | dbo.v_Collection.Name AS CollectionName, 33 | dbo.v_ClientCollectionMembers.ResourceID, 34 | dbo.v_ClientCollectionMembers.Name, 35 | dbo.v_ClientCollectionMembers.Domain, 36 | dbo.v_ClientCollectionMembers.SiteCode, 37 | dbo.v_ClientCollectionMembers.IsClient 38 | FROM dbo.v_ClientCollectionMembers INNER JOIN 39 | dbo.v_Collection ON dbo.v_ClientCollectionMembers.CollectionID = dbo.v_Collection.CollectionID 40 | WHERE (dbo.v_ClientCollectionMembers.Name = '$ComputerName') 41 | ORDER BY CollectionName 42 | "@ 43 | 44 | $DatabaseName = "CM_$SiteCode" 45 | $QueryTimeout = 120 46 | $ConnectionTimeout = 30 47 | #Action of connecting to the Database and executing the query and returning results if there were any. 48 | $conn = New-Object System.Data.SqlClient.SQLConnection 49 | $ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $ServerName,$DatabaseName,$ConnectionTimeout 50 | $conn.ConnectionString = $ConnectionString 51 | try { 52 | $conn.Open() 53 | Write-Verbose "connection opened successfully" 54 | } 55 | catch { 56 | Write-Error $_.Exception.Message 57 | break 58 | } 59 | $cmd = New-Object System.Data.SqlClient.SqlCommand($qtext,$conn) 60 | $cmd.CommandTimeout = $QueryTimeout 61 | $ds = New-Object System.Data.DataSet 62 | $da = New-Object System.Data.SqlClient.SqlDataAdapter($cmd) 63 | [void]$da.Fill($ds) 64 | $rowcount = $($ds.Tables).Rows.Count 65 | if ($rowcount -gt 0) { 66 | Write-Host "$rowcount rows returned" -ForegroundColor Green 67 | $($ds.Tables).Rows 68 | } 69 | -------------------------------------------------------------------------------- /collections/Get-CmObjectCollection.ps1: -------------------------------------------------------------------------------- 1 | function Get-CmObjectCollection { 2 | [CmdletBinding()] 3 | param ( 4 | [parameter(Mandatory=$True, HelpMessage="SMS Provider Name")] 5 | [ValidateNotNullOrEmpty()] 6 | [string] $Computer, 7 | [parameter(Mandatory=$True, HelpMessage="Site Code")] 8 | [ValidateLength(3,3)] 9 | [string] $SiteCode, 10 | [parameter(Mandatory=$True, HelpMessage="WMI Class Name")] 11 | [ValidateNotNullOrEmpty()] 12 | [string] $ClassName, 13 | [parameter(Mandatory=$False, HelpMessage="Credentials")] 14 | [System.Management.Automation.PSCredential] $Credential 15 | ) 16 | $Namespace = "ROOT\SMS\site_$SiteCode" 17 | try { 18 | if ($Credential) { 19 | $result = @(Get-WmiObject -Class $ClassName -ComputerName $Computer -Namespace $Namespace -Credential $Credential -ErrorAction SilentlyContinue) 20 | } 21 | else { 22 | $result = @(Get-WmiObject -Class $ClassName -ComputerName $Computer -Namespace $Namespace -ErrorAction SilentlyContinue) 23 | } 24 | return $result | Select-Object * -ExcludeProperty PSComputerName, Scope, Path, Options, ClassPath, 25 | Properties, SystemProperties, Qualifiers, Site, Container, __GENUS, __CLASS, __SUPERCLASS, 26 | __DYNASTY, __RELPATH, __PROPERTY_COUNT, __DERIVATION, __SERVER, __NAMESPACE, __PATH 27 | 28 | } 29 | catch { 30 | Write-Error $Error[0].Exception.Message 31 | } 32 | } 33 | 34 | <# 35 | if (!$cred) { $cred = (Get-Credential) } 36 | Get-CmObjectCollection -Computer "CM01" -SiteCode "P01" -ClassName "SMS_R_System" -Credential $cred 37 | Get-CmObjectCollection -Computer "CM01" -SiteCode "P01" -ClassName "SMS_G_System_WORKSTATION_STATUS" -Credential $cred 38 | #> 39 | -------------------------------------------------------------------------------- /collections/Get-ICmCollectionMembers.ps1: -------------------------------------------------------------------------------- 1 | #requires -Modules dbatools 2 | 3 | function Get-ICmCollectionMembers { 4 | param ( 5 | [parameter(Mandatory=$True, HelpMessage="Collection ID", ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True, Position=0)] 6 | [ValidateLength(8,8)] 7 | [string] $CollectionID, 8 | [parameter(Mandatory=$True, HelpMessage="Collection ID")] 9 | [ValidateNotNullOrEmpty()] 10 | [string] $SqlInstance, 11 | [parameter(Mandatory=$True, HelpMessage="Collection ID")] 12 | [ValidateLength(3,3)] 13 | [string] $SiteCode 14 | ) 15 | try { 16 | $query = "SELECT DISTINCT 17 | v_ClientCollectionMembers.Name, 18 | v_ClientCollectionMembers.ResourceID, 19 | v_ClientCollectionMembers.Domain, 20 | v_ClientCollectionMembers.SiteCode, 21 | v_ClientCollectionMembers.IsClient, 22 | vWorkstationStatus.ClientVersion, 23 | vWorkstationStatus.UserName, 24 | vWorkstationStatus.LastHardwareScan, 25 | vWorkstationStatus.OperatingSystem, 26 | v_R_System.AD_Site_Name0 as ADSiteName, 27 | v_R_System.Last_Logon_Timestamp0 as LastLogon 28 | FROM v_ClientCollectionMembers INNER JOIN 29 | vWorkstationStatus ON v_ClientCollectionMembers.ResourceID = vWorkstationStatus.ResourceID INNER JOIN 30 | v_R_System ON v_ClientCollectionMembers.ResourceID = v_R_System.ResourceID 31 | WHERE (v_ClientCollectionMembers.CollectionID = '$CollectionID') 32 | ORDER BY Name" 33 | @(Invoke-DbaQuery -SqlInstance $SqlInstance -Database "CM_$SiteCode" -Query $query -ErrorAction Stop) 34 | } 35 | catch { 36 | Write-Error $Error[0].Exception.Message 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /collections/Import-CMCollectionMembersFromFile.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(SupportsShouldProcess=$True)] 2 | param ( 3 | [parameter(Mandatory=$True)] 4 | [ValidateNotNullOrEmpty()] 5 | [string] $InputFile, 6 | [parameter(Mandatory=$True)] 7 | [ValidateNotNullOrEmpty()] 8 | [string] $CollectionID, 9 | [parameter(Mandatory=$False)] 10 | [string] $ServerName = "cm01.contoso.local", 11 | [parameter(Mandatory=$False)] 12 | [string] $SiteCode = "P01", 13 | [parameter(Mandatory=$False)] 14 | [string] $CommentChar = ';' 15 | ) 16 | .\tools\Import-CMModule.ps1 17 | 18 | if (!(Test-Path $InputFile)) { 19 | Write-Warning "$InputFile not found!!" 20 | break 21 | } 22 | $computers = Get-Content -Path $InputFile | ? {!$_.ToString().StartsWith($CommentChar)} 23 | if ($computers.Count -lt 1) { 24 | Write-Warning "$InputFile contains no device names" 25 | break 26 | } 27 | Write-Host "$($computers.count) computers imported from file" -ForegroundColor Cyan 28 | 29 | $members = .\tools\Get-CmCollectionMember.ps1 -CollectionID $CollectionID -ServerName $ServerName -SiteCode $SiteCode 30 | $count1 = 0 31 | $count2 = 0 32 | if ($members.Count -gt 0) { 33 | Write-Host "$($members.Count) collection members found" -ForegroundColor Cyan 34 | $memberNames = ($members).ComputerName | Sort-Object ComputerName 35 | foreach ($comp in $computers) { 36 | Write-Verbose "computer: $comp" 37 | if ($memberNames -contains $comp) { 38 | $data = [ordered]@{ 39 | ComputerName = $comp 40 | CollectionID = $CollectionID 41 | Action = 'Already Member' 42 | DateStamp = (Get-Date).DateTime 43 | } 44 | $count1++ 45 | #Write-Host "$comp is already a member" 46 | } 47 | else { 48 | if ($WhatIfPreference) { 49 | $action = 'Would be Added' 50 | } 51 | else { 52 | $action = 'Added' 53 | } 54 | .\tools\Add-CMDeviceToCollection.ps1 -ComputerName $comp -CollectionID $CollectionID -ServerName $ServerName -SiteCode $SiteCode 55 | $data = [ordered]@{ 56 | ComputerName = $comp 57 | CollectionID = $CollectionID 58 | Action = $action 59 | DateStamp = (Get-Date).DateTime 60 | } 61 | $count2++ 62 | } 63 | New-Object -TypeName PSObject -Property $data 64 | Start-Sleep -Seconds 2 65 | } # foreach 66 | Write-Verbose "$count1 already members" 67 | Write-Verbose "$count2 added to collection" 68 | } 69 | -------------------------------------------------------------------------------- /collections/Select-CmCollectionFromList.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .DESCRIPTION 3 | Display ConfigMgr collections in grid view for selection 4 | .PARAMETER AdoConnection 5 | ADO database connection object (opened) 6 | .EXAMPLE 7 | $conn = Get-CmAdoConnection -SQLServerName "cm01.contoso.local" -DatabaseName "CM_P01" -SiteCode "P01" 8 | $collID = Select-CmCollectionFromList.ps1 -AdoConnection $conn 9 | $conn.Close() 10 | #> 11 | 12 | [CmdletBinding()] 13 | param ( 14 | [parameter(Mandatory=$True)] 15 | [ValidateNotNull()] 16 | $AdoConnection 17 | ) 18 | $QueryTimeout = 120 19 | $query = "SELECT DISTINCT CollectionID, Name, MemberCount FROM dbo.v_Collection ORDER BY Name" 20 | $cmd = New-Object System.Data.SqlClient.SqlCommand($query,$AdoConnection) 21 | $cmd.CommandTimeout = $QueryTimeout 22 | $ds = New-Object System.Data.DataSet 23 | $da = New-Object System.Data.SqlClient.SqlDataAdapter($cmd) 24 | [void]$da.Fill($ds) 25 | $rowcount = $($ds.Tables).Rows.Count 26 | if ($rowcount -gt 0) { 27 | Write-Verbose "$rowcount collections returned" 28 | try { 29 | $x = $($ds.Tables).Rows | Out-GridView -Title "Select Collection" -OutputMode Single 30 | Write-Output $x | Select-Object -ExpandProperty CollectionID 31 | } 32 | catch { 33 | Write-Error $Error[0].Exception.Message 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /collections/customcollections.json: -------------------------------------------------------------------------------- 1 | { 2 | "Accounting": { 3 | "users": { 4 | "limiting": "All Users", 5 | "queryrule": "select SMS_R_USER.ResourceID,SMS_R_USER.ResourceType,SMS_R_USER.Name,SMS_R_USER.UniqueUserName,SMS_R_USER.WindowsNTDomain from SMS_R_User where SMS_R_User.UserGroupName = 'CONTOSO\\Users-Accounting'", 6 | "schedule": 1, 7 | "folder": "UserCollection\\Departments\\Accounting" 8 | }, 9 | "devices": { 10 | "limiting": "All Desktop and Server Clients", 11 | "queryrule": "select SMS_R_SYSTEM.ResourceID,SMS_R_SYSTEM.ResourceType,SMS_R_SYSTEM.Name,SMS_R_SYSTEM.SMSUniqueIdentifier,SMS_R_SYSTEM.ResourceDomainORWorkgroup,SMS_R_SYSTEM.Client from SMS_R_System where SMS_R_System.SystemGroupName = 'CONTOSO\\Computers-Accounting'", 12 | "schedule": 1, 13 | "folder": "DeviceCollection\\Departments\\Accounting" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Summary": { 3 | "query": "SELECT ( SELECT COUNT(*) FROM v_R_SYSTEM ) AS Devices,( SELECT COUNT(*) FROM v_R_USER ) AS Users", 4 | "properties": "Devices,Users" 5 | }, 6 | "Devices": { 7 | "query": "select distinct cs.Name0 as Name,cs.ResourceID,cs.Manufacturer0 as Manufacturer,sys.Operating_System_Name_and0 as OSName,sys.Build01 as OSBuild,cs.Model0 as Model,round(cast(pm.TotalPhysicalMemory0 as float)/1024/1024, 1) as TotalMemory,cs.SystemType0 as SystemType,sys.AD_Site_Name0 as ADSiteName,cs.UserName0 as UserName,sys.Client_Version0 as ClientVersion,sys.SID0 as SID,sys.AADDeviceID,ws.LastHardwareScan as LastHWScan,ws.LastDDR from v_GS_COMPUTER_SYSTEM cs inner join v_R_System sys on cs.ResourceID = sys.ResourceID inner join vWorkstationStatus ws on cs.ResourceID = ws.ResourceID inner join v_GS_X86_PC_MEMORY pm on cs.ResourceID = pm.ResourceID order by cs.Name0", 8 | "properties": "Name,ResourceID,OSName,OSBuild,Manufacturer,Model,TotalMemory,SystemType,ADSiteName,UserName,ClientVersion,SID,AADDeviceID,LastHWScan,LastDDR" 9 | }, 10 | "OperatingSystems": { 11 | "query": "select distinct Caption0 as OSName,BuildNumber0 as BuildNum, case when (BuildNumber0 = 18363) then '1909' when (BuildNumber0 = 18362) then '1903' when (BuildNumber0 = 17763) then '1809' when (BuildNumber0 = 17134) then '1803' when (BuildNumber0 = 16299) then '1709' when (BuildNumber0 = 15063) then '1703' when (BuildNumber0 = 14393) then '1607' when (BuildNumber0 = 10586) then '1511' when (BuildNumber0 = 10240) then '1507' else '' end as Build, CSDVersion0 as SvcPack, COUNT(*) as Devices from v_GS_OPERATING_SYSTEM group by Caption0,BuildNumber0,CSDVersion0 order by Caption0,BuildNumber0", 12 | "properties": "OSName,BuildNum,Build,SvcPack,Devices" 13 | }, 14 | "Models": { 15 | "query": "select distinct Manufacturer0 as Manufacturer, Model0 as Model, Count(*) as Devices from dbo.v_GS_COMPUTER_SYSTEM group by Manufacturer0,Model0 order by Manufacturer0,Model0", 16 | "properties": "Manufacturer,Model,Devices" 17 | }, 18 | "Disks": { 19 | "query": "select distinct ld.SystemName0 as Name, ld.Size0 as Capacity, ld.FreeSpace0 as FreeSpace, cs.Model0 as Model, case when (FreeSpace0 < 20000) then 'No' else 'Yes' end as Ready from v_GS_LOGICAL_DISK ld inner join v_GS_COMPUTER_SYSTEM cs on cs.ResourceID = ld.ResourceID where ld.DeviceID0 = 'C:' order by ld.SystemName0", 20 | "properties": "Name,Model,Capacity,FreeSpace,Ready" 21 | }, 22 | "Memory": { 23 | "query": "select sys.Name0 as Name,pm.ResourceID,SUM(pm.Capacity0) as Memory from v_GS_PHYSICAL_MEMORY pm inner join v_R_SYSTEM sys on pm.ResourceID = sys.ResourceID group by sys.Name0,pm.ResourceID order by sys.Name0", 24 | "properties": "Name,ResourceID,Memory" 25 | }, 26 | "Software": { 27 | "query": "select distinct ARPDisplayName0 as ProductName,ProductVersion0 as Version,Publisher0 as Publisher, ProductCode0 as ProductCode, COUNT(*) as Installs from v_GS_INSTALLED_SOFTWARE_CATEGORIZED where (LTRIM(ARPDisplayname0) <> '') and (SUBSTRING(ARPDisplayName0,0,2) <> '..') group by ARPDisplayName0,ProductVersion0,Publisher0,ProductCode0 order by ARPDisplayName0,ProductVersion0", 28 | "properties": "Installs,ProductName,Version,Publisher,ProductCode" 29 | }, 30 | "ADSites": { 31 | "query": "select distinct sys.AD_Site_Name0 as ADSite, COUNT(*) as Devices from v_R_SYSTEM as sys group by AD_Site_Name0 order by AD_Site_Name0", 32 | "properties": "ADSite,Devices" 33 | }, 34 | "Gateways": { 35 | "query": "select distinct DefaultIPGateway0 as Gateway, COUNT(*) as Devices from v_GS_NETWORK_ADAPTER_CONFIGURATION where DefaultIPGateway0 IS NOT NULL group by DefaultIPGateway0 order by Devices desc", 36 | "properties": "Gateway,Devices" 37 | }, 38 | "DistPoints": { 39 | "query": "select Servername,SMSSiteCode as Site,Description,Type,IsPXE as PXE,IsDoincEnabled as DOINC, IsBITS as BITS,IsMulticast as MCast,IsPullDP as PullDP,IsPeerDP as PeerDP, SslState as SSL,PreStagingAllowed as Prestage from v_DistributionPoints order by ServerName", 40 | "properties": "Servername,Site,Description,Type,PXE,DOINC,BITS,MCast,PullDP,PeerDP,SSL,Prestage" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /crap/Get-CMAdoConnection.ps1: -------------------------------------------------------------------------------- 1 | function Get-CmAdoConnection { 2 | <# 3 | .DESCRIPTION 4 | Returns an ADO connection object to an open connection to a ConfigMgr SQL database server 5 | .PARAMETER SQLServerName 6 | Name of ConfigMgr SQL Server hostname 7 | .PARAMETER DatabaseName 8 | Name of the SQL instance Database to connect to 9 | .PARAMETER ConnectionTimeOut 10 | Optional SQL connection timeout value. Default is 30. 11 | .PARAMETER QueryTimeout 12 | Optional SQL query timeout value. Default is 120. 13 | #> 14 | [CmdletBinding(SupportsShouldProcess=$True)] 15 | param ( 16 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr SQL Server hostname")] 17 | [ValidateNotNullOrEmpty()] 18 | [string] $SQLServerName, 19 | [parameter(Mandatory=$True, HelpMessage="SQL Server database name")] 20 | [ValidateNotNullOrEmpty()] 21 | [string] $DatabaseName, 22 | [parameter(Mandatory=$False, HelpMessage="SQL connection timeout value")] 23 | [int] $ConnectionTimeout = 30, 24 | [parameter(Mandatory=$False, HelpMessage="SQL query timeout value")] 25 | [int]$QueryTimeout = 120 26 | ) 27 | Write-Verbose "opening new connection to $SQLServerName" 28 | $conn = New-Object System.Data.SqlClient.SQLConnection 29 | $ConnectionString = "Server={0};Database={1};Integrated Security=True;Connect Timeout={2}" -f $SQLServerName,$DatabaseName,$ConnectionTimeout 30 | $conn.ConnectionString = $ConnectionString 31 | try { 32 | $conn.Open() 33 | Write-Output $conn 34 | } 35 | catch { 36 | Write-Error $Error[0].Exception.Message 37 | break 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /demo/Create-DslShare.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [parameter()][ValidateLength(1,1)][string] $DriveLetter = "E", 4 | [parameter()][ValidateNotNullOrEmpty()][string]$InputFile = "folders.txt", 5 | [parameter()][ValidateNotNullOrEmpty()][string]$RootFolder = "SOURCES" 6 | ) 7 | $ErrorActionPreference = 'stop' 8 | try { 9 | $rootPath = "$DriveLetter`:\$RootFolder" 10 | if (!(Test-Path $rootPath)) { 11 | mkdir $rootPath -Force 12 | Write-Verbose "created folder: $rootPath" 13 | } 14 | $folders = Get-Content $InputFile 15 | foreach ($folder in $folders) { 16 | $fpath = Join-Path -Path $rootPath -ChildPath $folder 17 | if (!(Test-Path $fpath)) { 18 | mkdir $fpath -Force 19 | Write-Verbose "created folder: $fpath" 20 | } 21 | else { 22 | Write-Verbose "folder exists: $fpath" 23 | } 24 | } 25 | $shareName = "$RootFolder`$" 26 | if ($shareName -notin (Get-SmbShare).Name) { 27 | Write-Verbose "creating share: $shareName" 28 | New-SmbShare -Path $rootPath -Name "$shareName" 29 | } 30 | Write-Host "finished processing" 31 | } 32 | catch {} 33 | -------------------------------------------------------------------------------- /demo/Download-AppSources.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param( 3 | [parameter()][ValidateNotNullOrEmpty()][string]$InputFile = "downloads.txt", 4 | [parameter()][ValidateNotNullOrEmpty()][string]$rootPath = "E:\SOURCES" 5 | ) 6 | try { 7 | $apps = Get-Content $InputFile 8 | foreach ($app in $apps) { 9 | $appdata = $app -split '~' 10 | $appPath = $appdata[0] 11 | $appSource = $appdata[1] 12 | if ($appdata.Count -eq 3) { 13 | $filename = $appdata[2] 14 | } 15 | else { 16 | $filename = $($appSource -split '/' | select -Last 1) -replace '%20','_' 17 | } 18 | $destPath = Join-Path -Path $rootPath -ChildPath $appPath 19 | if (!(Test-Path $destPath)) { 20 | mkdir $destPath -Force 21 | Write-Verbose "created folder: $destPath" 22 | } 23 | $destination = Join-Path -Path $destPath -ChildPath "$filename" 24 | if (!(Test-Path $destination)) { 25 | #Invoke-WebRequest -Uri $appSource -OutFile $destination 26 | [void](New-Object System.Net.WebClient).DownloadFile($appSource, $destination) 27 | } 28 | else { 29 | Write-Verbose "file exists: $destination" 30 | } 31 | } 32 | Write-Host "finished processing" 33 | } 34 | catch { 35 | Write-Error $_.Exception.Message 36 | } 37 | -------------------------------------------------------------------------------- /demo/Get-CmQueryData.ps1: -------------------------------------------------------------------------------- 1 | #requires -module dbatools 2 | <# 3 | .SYNOPSIS 4 | Demonstrate dbatools with query files and ConfigMgr SQL data 5 | .DESCRIPTION 6 | (same) 7 | .PARAMETER SqlHost 8 | Name of ConfigMgr site database SQL Server host 9 | .PARAMETER SiteCode 10 | ConfigMgr site code 11 | .PARAMETER BaseUrl 12 | URL Path to folder with queries.txt and .sql query files 13 | .EXAMPLE 14 | .\Get-CmQueryData.ps1 -SqlHost "cm01" -SiteCode "P01" 15 | .NOTES 16 | 1.0.0 - DS - 2019.03.28 - initial release 17 | ***************************************************************************** 18 | *** NO WARRANTY OR GUARANTEE OF ANY KIND!! *** 19 | *** USE AT YOUR OWN RISK / DO NOT USE IN A PRODUCTION ENVIRONMENT *** 20 | *** AUTHOR ASSUMES NO LIABILITY OR RESPONSIBLITY FOR ANY USE OF THIS CODE *** 21 | ***************************************************************************** 22 | #> 23 | [CmdletBinding()] 24 | param ( 25 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr database SQL Server hostname")] 26 | [ValidateNotNullOrEmpty()] 27 | [string] $SqlHost, 28 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr Site Code")] 29 | [ValidateLength(3,3)] 30 | [string] $SiteCode, 31 | [parameter(Mandatory=$False, HelpMessage="URL to common source files")] 32 | [ValidateLength(3,3)] 33 | [string] $BaseUrl = 'https://raw.githubusercontent.com/Skatterbrainz/sccm/master/queries' 34 | ) 35 | try { 36 | Write-Verbose "requesting list of queries from $BaseUrl/queries.txt" 37 | $qlist = (Invoke-RestMethod -Method Get -UseBasicParsing -Uri "$BaseUrl/queries.txt" -ErrorAction SilentlyContinue) 38 | $qlist = $qlist -split [char]10 39 | Write-Verbose "sending list to gridview for user selection" 40 | $qname = $qlist | Out-GridView -Title "Select Query to run, or Cancel to quit" -OutputMode Single 41 | if ($qname) { 42 | Write-Verbose "selected: $qname ($BaseUrl/$qname`.sql)" 43 | $qtext = Invoke-RestMethod -Method Get -UseBasicParsing -Uri "$BaseUrl/$qname`.sql" -ErrorAction Stop 44 | Invoke-DbaQuery -SqlInstance $SqlHost -Database "CM_$SiteCode" -Query $qtext 45 | } 46 | } 47 | catch { 48 | Write-Warning $Error[0].Exception.Message 49 | } 50 | -------------------------------------------------------------------------------- /demo/Get-NetworkInfo.ps1: -------------------------------------------------------------------------------- 1 | 2 | function Get-NetworkInfo { 3 | param ( 4 | [parameter(Mandatory=$True)] 5 | [string] $ComputerName 6 | ) 7 | $x = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $ComputerName | 8 | Select Description, MACAddress, IPAddress 9 | 10 | foreach($nic in $x) { 11 | if ($($nic.IPAddress).Count -gt 0) { 12 | $ip = $nic.IPAddress[0] 13 | } 14 | else { 15 | $ip = "" 16 | } 17 | $props = [ordered]@{ 18 | Description = $nic.Description 19 | MACAddress = $nic.MACAddress 20 | IPAddress = $ip 21 | } 22 | New-Object PSObject -Property $props 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /demo/cb_chocolatey.ps1: -------------------------------------------------------------------------------- 1 | # sccm configuration baseline script to enforce chocolatey installation 2 | # when ci_chocolatey.ps1 returns $False 3 | 4 | Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) 5 | -------------------------------------------------------------------------------- /demo/ci_chocolatey.ps1: -------------------------------------------------------------------------------- 1 | # configuration item for SCCM baseline detection rule 2 | # used with cb_chocolatey.ps1 3 | if (Test-Path "$($env:PROGRAMDATA)\chocolatey\choco.exe") { 4 | Write-Output $True 5 | } 6 | else { 7 | Write-Output $False 8 | } 9 | -------------------------------------------------------------------------------- /demo/downloads.txt: -------------------------------------------------------------------------------- 1 | Apps\7-Zip~https://www.7-zip.org/a/7z1900-x64.msi 2 | Apps\Microsoft~https://go.microsoft.com/fwlink/?linkid=2084648&Channel=Dev&language=en&Consent=0&IID=cb953dea-c69e-5e08-955c-132fa2eb30c3 3 | Apps\Mozilla\Firefox~https://download-installer.cdn.mozilla.net/pub/firefox/releases/70.0/win64/en-US/Firefox%20Setup%2070.0.msi 4 | Apps\Google\Chrome~https://dl.google.com/tag/s/dl/chrome/install/googlechromestandaloneenterprise64.msi 5 | Apps\Notepad++~http://download.notepad-plus-plus.org/repository/7.x/7.8.1/npp.7.8.1.Installer.x64.exe 6 | Apps\VLC~https://ftp.osuosl.org/pub/videolan/vlc/3.0.8/win64/vlc-3.0.8-win64.exe 7 | Scripts\WSUS~https://damgoodadmin.com/download/invoke-dgasoftwareupdatemaintenance/?wpdmdl=326&refresh=5db464511e44c1572103249~Invoke-DgaSoftwareUpdateMaintenance.zip 8 | Scripts\OSD~https://raw.githubusercontent.com/Skatterbrainz/sccm/master/OSD/Set-ComputerNameX.ps1 9 | Scripts\OSD~https://raw.githubusercontent.com/SCConfigMgr/ConfigMgr/master/Operating%20System%20Deployment/Drivers/Invoke-CMApplyDriverPackage.ps1 10 | Tools\DriverAutomationTool~https://gallery.technet.microsoft.com/Driver-Tool-Automate-9ddcc010/file/224244/1/Driver%20Automation%20Tool.zip 11 | Tools\ConfigMgrWebService~https://gallery.technet.microsoft.com/ConfigMgr-WebService-100-572825b2/file/223724/1/ConfigMgr%20WebService%201.8.0.zip 12 | Tools\SQL~https://ola.hallengren.com/scripts/MaintenanceSolution.sql 13 | Tools\CMPT~https://gallery.technet.microsoft.com/ConfigMgr-2012-R2-e52919cd/file/225287/1/ConfigMgr%20Prerequisites%20Tool%203.0.5.zip 14 | Setup\MEMCM~http://download.microsoft.com/download/D/8/E/D8E795CE-44D7-40B7-9067-D3D1313865E5/SC_Configmgr_SCEP_TechPreview1907.exe 15 | Setup\SQL~https://download.microsoft.com/download/E/6/4/E6477A2A-9B58-40F7-8AD6-62BB8491EA78/SQLServerReportingServices.exe 16 | Setup\SQL~https://download.microsoft.com/download/1/9/8/1986c4a9-480b-4a46-8088-2778e0abcc8a/SSMS-Setup-ENU.exe 17 | Setup\SQL~https://download.microsoft.com/download/C/4/F/C4F908C9-98ED-4E5F-88D5-7D6A5004AEBD/SQLServer2017-KB4515579-x64.exe 18 | Setup\CM~http://download.microsoft.com/download/D/8/E/D8E795CE-44D7-40B7-9067-D3D1313865E5/SC_Configmgr_SCEP_TechPreview1907.exe 19 | Setup\ADK~https://go.microsoft.com/fwlink/?linkid=2086042 20 | Setup\ADK~https://go.microsoft.com/fwlink/?linkid=2087112 21 | Setup\MDT~https://download.microsoft.com/download/3/3/9/339BE62D-B4B8-4956-B58D-73C4685FC492/MicrosoftDeploymentToolkit_x64.msi 22 | Setup\Scripts~https://raw.githubusercontent.com/Skatterbrainz/sccm/master/demo/Create-DslShare.ps1 23 | Setup\Scripts~https://raw.githubusercontent.com/Skatterbrainz/sccm/master/demo/folders.txt 24 | -------------------------------------------------------------------------------- /demo/folders.txt: -------------------------------------------------------------------------------- 1 | Apps\7-zip 2 | Apps\Google\Chrome 3 | Apps\Microsoft\O365ProPlus 4 | Apps\Mozilla\Firefox 5 | Apps\Notepad++ 6 | Apps\VLC 7 | Certs 8 | DrvPkg 9 | DrvSrc 10 | MDT\BootImages 11 | MDT\Settings 12 | MDT\Tools 13 | OSImages\W10_1903 14 | OSImages\W10_1909 15 | Scripts\Demos 16 | Scripts\OSD 17 | Scripts\WSUS 18 | Tools\ConfigMgrWebService 19 | Tools\DriverAutomationTool 20 | Tools\SQL 21 | Tools\Wallpaper 22 | OSDLOGS 23 | UPDATES 24 | -------------------------------------------------------------------------------- /devices/Collect-ClientLogFiles.ps1: -------------------------------------------------------------------------------- 1 | # for "Run Script" feature in ConfigMgr 2 | # david stein - 12/13/2017 3 | $LogPath = 'c:\windows\ccm\logs' 4 | $Upload = '\\cm01.contoso.com\ClientLogs$\'+$env:COMPUTERNAME 5 | if (!(Test-Path $Upload)) { 6 | mkdir $Upload 7 | } 8 | if (Test-Path $Upload) { 9 | robocopy $LogPath $Upload *.log /R:1 /W:3 10 | Write-Output 0 11 | } 12 | else { 13 | Write-Output -1 14 | } 15 | -------------------------------------------------------------------------------- /devices/Collect-SystemEventLogs.ps1: -------------------------------------------------------------------------------- 1 | # for use with ConfigMgr run script feature 2 | # David Stein - 12/11/2017 3 | $LogName = ($env:COMPUTERNAME)+'-system-errors.csv' 4 | $LogPath = '\\cm1.contoso.com\clientlogs$' 5 | $LogFile = $LogPath+'\'+$LogName 6 | Get-EventLog -LogName System -Newest 25 -EntryType Error | ConvertTo-Csv -NoTypeInformation | Out-File $LogFile 7 | Write-Output 0 8 | -------------------------------------------------------------------------------- /devices/Get-CMDeviceInfo.ps1: -------------------------------------------------------------------------------- 1 | #requires -version 3.0 2 | <# 3 | .DESCRIPTION 4 | Return query results for specific devices within ConfigMgr SQL database 5 | .PARAMETER ServerName 6 | ConfigMgr SQL Server hostname 7 | .PARAMETER SiteCode 8 | ConfigMgr site code 9 | .PARAMETER ComputerNames 10 | Names of computers to query information about 11 | .EXAMPLE 12 | $data = .\Get-CMDeviceInfo.ps1 -ServerName "cm01.contoso.local" -SiteCode "P01" -ComputerNames "DT123","DT456" 13 | .NOTES 14 | 1.0.1 - DS - Initial release 15 | 1.0.2 - DS - fixed SQL query to correct outer join issue 16 | #> 17 | 18 | [CmdletBinding()] 19 | param ( 20 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr SQL Server host name")] 21 | [ValidateNotNullOrEmpty()] 22 | [string] $ServerName, 23 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr site code")] 24 | [ValidateNotNullOrEmpty()] 25 | [string] $SiteCode, 26 | [parameter(Mandatory=$True, HelpMessage="Computer Names to query")] 27 | [ValidateNotNullOrEmpty()] 28 | [string[]] $ComputerNames 29 | ) 30 | Write-Verbose "----------------------------------------------" 31 | if ($ComputerNames.Count -gt 1) { 32 | Write-Verbose "(Get-CmDeviceInfo - $($ComputerNames.Count) names)" 33 | } 34 | else { 35 | Write-Verbose "(Get-CmDeviceInfo - $ComputerNames)" 36 | } 37 | $DatabaseName = "CM_$SiteCode" 38 | Write-Verbose "database name is $DatabaseName" 39 | $queryBase = @" 40 | SELECT DISTINCT 41 | dbo.v_R_System.Name0 AS [Name], 42 | dbo.v_R_System.ResourceID, 43 | dbo.v_R_System.AD_Site_Name0 AS [ADSite], 44 | dbo.vWorkstationStatus.ClientVersion, 45 | dbo.vWorkstationStatus.LastHardwareScan AS [LastHwScan], 46 | DATEDIFF(dd,dbo.vWorkstationStatus.LastHardwareScan,GETDATE()) AS InvAge, 47 | dbo.vWorkstationStatus.LastPolicyRequest, 48 | dbo.vWorkstationStatus.LastHealthEvaluationResult AS [LastHealthEval], 49 | dbo.v_GS_COMPUTER_SYSTEM.Model0 AS [Model], 50 | dbo.v_GS_OPERATING_SYSTEM.Caption0 AS [OperatingSystem], 51 | CASE 52 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 10586) THEN '1511' 53 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 14393) THEN '1607' 54 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 15063) THEN '1703' 55 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 16299) THEN '1709' 56 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 17134) THEN '1803' 57 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 17604) THEN '1809' 58 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 7601) THEN 'SP1' 59 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 9600) THEN 'RTM' 60 | ELSE dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 END AS OsBuild, 61 | dbo.vWorkstationStatus.LastDDR, 62 | dbo.vWorkstationStatus.SystemType, 63 | CASE 64 | WHEN (dbo.vWorkstationStatus.IsVirtualMachine = 1) THEN 'Y' 65 | ELSE 'N' END AS IsVM, 66 | dbo.vWorkstationStatus.UserName, 67 | dbo.vWorkstationStatus.UserDomain, 68 | dbo.v_GS_SYSTEM_ENCLOSURE.SerialNumber0 AS [SerialNumber] 69 | FROM 70 | dbo.v_R_System 71 | LEFT OUTER JOIN 72 | dbo.v_GS_SYSTEM_ENCLOSURE ON dbo.v_R_System.ResourceID = dbo.v_GS_SYSTEM_ENCLOSURE.ResourceID 73 | LEFT OUTER JOIN 74 | dbo.v_GS_OPERATING_SYSTEM ON dbo.v_R_System.ResourceID = dbo.v_GS_OPERATING_SYSTEM.ResourceID 75 | LEFT OUTER JOIN 76 | dbo.v_GS_COMPUTER_SYSTEM ON dbo.v_R_System.ResourceID = dbo.v_GS_COMPUTER_SYSTEM.ResourceID 77 | LEFT OUTER JOIN 78 | dbo.vWorkstationStatus ON dbo.v_R_System.ResourceID = dbo.vWorkstationStatus.ResourceID 79 | "@ 80 | $query = $queryBase 81 | if ($ComputerNames.Count -gt 1) { 82 | $complist = ($ComputerNames | %{"'$_'"}) -join ',' 83 | $query += " WHERE (dbo.v_R_System.Name0 IN ($complist)) ORDER BY dbo.v_R_System.Name0" 84 | } 85 | else { 86 | $query += " WHERE (dbo.v_R_System.Name0 = '$ComputerNames')" 87 | } 88 | #Write-Verbose $query 89 | .\tools\Get-CMSQLQueryData.ps1 -Query $query -SQLServerName $ServerName -SiteCode $SiteCode 90 | -------------------------------------------------------------------------------- /devices/Get-CmDeviceSummary.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [string] $($env:COMPUTERNAME), 4 | [string] $SiteCode 5 | ) 6 | 7 | Write-Host "gathering data from site server: $SiteServer ($SiteCode)" -ForegroundColor Cyan 8 | 9 | try { 10 | $smsns = "root\sms\site_$SiteCode" 11 | 12 | $q1 = "select resourceid,name,adsitename,client,OperatingSystemNameandVersion,isvirtualmachine,lastlogontimestamp from sms_r_system" 13 | $q2 = "select resourceid,name,manufacturer,model from sms_g_system_computer_system" 14 | $q3 = "select ipsubnets,name from sms_r_system" 15 | $q5 = "select resourceid,caption,buildnumber,lastbootuptime,installdate from sms_g_system_operating_system" 16 | 17 | # get all devices 18 | $x1 = Get-CimInstance -Namespace $smsns -ComputerName $SiteServer -Query $q1 | 19 | Select-Object resourceid,name,adsitename,client,isvirtualmachine,lastlogontimestamp 20 | 21 | # get clients with inventory data 22 | $x2 = Get-CimInstance -Namespace $smsns -ComputerName $SiteServer -Query $q2 | 23 | Select-Object resourceid,name,manufacturer,model 24 | 25 | $models = $x2 | Select-Object Model -Unique | ForEach-Object { 26 | $model = $_.Model 27 | [pscustomobject]@{ 28 | Model = $model 29 | Count = @($x2 | ?{$_.Model -eq $model}).Count 30 | } 31 | } 32 | 33 | # get unique device IP subnets 34 | $x3 = Get-CimInstance -Namespace $smsns -ComputerName $SiteServer -Query $q3 | 35 | Select-Object ipsubnets,name 36 | 37 | # get active client subnets 38 | $x4 = $x3 | ForEach-Object { 39 | try { 40 | $ipsub = @($_.IPSubnets | ?{ !$_.StartsWith('169') })[0] 41 | } 42 | catch { 43 | $ipsub = $null 44 | } 45 | [pscustomobject]@{ 46 | Name = $_.Name 47 | Subnet = $ipsub 48 | } 49 | } 50 | 51 | # get unique subnets in sorted order 52 | $unique_subnets = $x4 | Select-Object subnet -Unique | 53 | Sort-Object Subnet | 54 | Select-Object -ExpandProperty Subnet 55 | 56 | $subnetcounts = $unique_subnets | ForEach-Object { 57 | $subnet = $_ 58 | [pscustomobject]@{ 59 | Subnet = $subnet 60 | Devices = @($x4 | ?{$_.Subnet -eq $subnet}).Count 61 | } 62 | } 63 | 64 | $x5 = Get-CimInstance -Namespace $smsns -ComputerName $SiteServer -Query $q5 | 65 | Select-Object resourceid,caption,buildnumber,lastbootuptime,installdate 66 | 67 | $oscounts = $x5 | Select-Object Caption -Unique | ForEach-Object { 68 | $cap = $_.Caption 69 | [pscustomobject]@{ 70 | Caption = $cap 71 | Count = @($x5 | ?{$_.caption -eq $cap}).Count 72 | } 73 | } 74 | $clients = $x1 | ? {$_.Client -eq 1} 75 | $clientcounts = [pscustomobject]@{ 76 | Clients = $($clients.Count) 77 | NoClient = $($x1.Count - $clients.Count) 78 | } 79 | 80 | } 81 | catch { 82 | Write-Error $Error[0].Exception.Message 83 | } 84 | -------------------------------------------------------------------------------- /devices/Get-NextAdComputerName.ps1: -------------------------------------------------------------------------------- 1 | function Get-NextAdComputerName { 2 | param ($Prefix, $Digits) 3 | $clist = Get-ADComputer -Filter * -Properties Name -ErrorAction SilentlyContinue| 4 | ?{$_.Name -match "$Prefix[0-9]{$Digits}"} | 5 | Select -ExpandProperty Name | 6 | Sort Name 7 | if ($clist.Count -gt 0) { 8 | $n = $clist.Count 9 | [int]$x = [convert]::ToInt32($clist[$n-1].Replace($Prefix,""),10) 10 | [string]$next = $x + 1 11 | while ($next.Length -lt $Digits) { 12 | $next = "0" + $next 13 | } 14 | } 15 | $($Prefix + $next) 16 | } -------------------------------------------------------------------------------- /devices/Get-OSComputerOU.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OSComputerOU { 2 | param( $ComputerName = $env:COMPUTERNAME ) 3 | $Filter = "(&(objectCategory=Computer)(Name=$ComputerName))" 4 | $DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher 5 | $DirectorySearcher.Filter = $Filter 6 | $SearcherPath = $DirectorySearcher.FindOne() 7 | $DistinguishedName = $SearcherPath.GetDirectoryEntry().DistinguishedName 8 | $OUName = ($DistinguishedName.Split(","))[1] 9 | return $OUName.SubString($OUName.IndexOf("=")+1) 10 | } 11 | -------------------------------------------------------------------------------- /devices/Remove-AdCmComputer.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Deletes computers from AD and ConfigMgr 4 | 5 | .DESCRIPTION 6 | Deletes computers from AD domain and ConfigMgr site using explicit input or file input 7 | 8 | .PARAMETER InputFile 9 | Name of TXT file with computer names to process. Overrides -ComputerName 10 | 11 | .PARAMETER ComputerName 12 | Explicit computer names to process 13 | 14 | .NOTES 15 | 2018-05-05 - DS - first time getting drunk 16 | 2018-07-05 - DS - added DeleteFrom parameter, no drinking this time 17 | 2018-08-31 - DS - added whatif support, still sober 18 | 19 | .EXAMPLE 20 | .\Remove-AdCmComputer.ps1 -ComputerName DT001 -SiteServer cm01.contoso.local -SiteCode P01 -DeleteFrom 'CM' 21 | 22 | .EXAMPLE 23 | .\Remove-AdCmComputer.ps1 -InputFile .\computers.txt -SiteServer cm01.contoso.local -SiteCode P01 24 | 25 | #> 26 | [CmdletBinding(SupportsShouldProcess=$True)] 27 | param ( 28 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr Site Server FQDN")] 29 | [ValidateNotNullOrEmpty()] 30 | [string] $SiteServer, 31 | [parameter(Mandatory=$True, HelpMessage="ConfigMgr Site Code")] 32 | [ValidateLength(3,3)] 33 | [string] $SiteCode, 34 | [parameter(Mandatory=$False, HelpMessage="Input TXT File")] 35 | [string] $InputFile = "", 36 | [parameter(Mandatory=$False, HelpMessage="Computer Names")] 37 | [string[]] $ComputerName = "", 38 | [parameter(Mandatory=$False, HelpMessage="Delete from AD or ConfigMgr or Both")] 39 | [ValidateSet('BOTH','AD','CM')] 40 | [string] $DeleteFrom = 'BOTH' 41 | ) 42 | 43 | $time1 = Get-Date 44 | # find and delete the computer from AD 45 | $domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() 46 | $root = $domain.GetDirectoryEntry() 47 | $search = [System.DirectoryServices.DirectorySearcher]$root 48 | $forest = ([System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()).Forest.Name 49 | 50 | if (![string]::IsNullOrEmpty($InputFile)) { 51 | if (Test-Path $InputFile) { 52 | $ComputerName = Get-Content $InputFile 53 | } 54 | else { 55 | Write-Warning "ABORT: Input file not found: $InputFile" 56 | break 57 | } 58 | } 59 | foreach ($Computer in $ComputerName) { 60 | if ($DeleteFrom -eq 'AD' -or $DeleteFrom -eq 'BOTH') { 61 | Write-Verbose "searching domain for: $Computer" 62 | $search.Filter = "(&(objectClass=computer)(name=$Computer))" 63 | try { 64 | $result = $search.FindAll() | Foreach-Object {$_.GetDirectoryEntry() } 65 | if ($result) { 66 | if ($WhatIfPreference) { 67 | Write-Host "WHATIF: delete $Computer from $forest" -ForegroundColor Yellow 68 | } 69 | else { 70 | $result | Foreach-Object {$_.DeleteObject(0)} 71 | Write-Host "deleted from domain: $Computer" -ForegroundColor Cyan 72 | } 73 | } 74 | else { 75 | Write-Warning "$Computer not found in domain" 76 | } 77 | } 78 | catch { 79 | Write-Error $_.Exception.Message 80 | } 81 | } 82 | if ($DeleteFrom -eq 'CM' -or $DeleteFrom -eq 'BOTH') { 83 | try { 84 | $res = Get-WmiObject -Query "select * from SMS_R_SYSTEM WHERE Name='$Computer'" -ComputerName $SiteServer -Namespace "ROOT\SMS\site_$SiteCode" 85 | if ($res) { 86 | if ($WhatIfPreference) { 87 | Write-Host "WHATIF: delete $Computer from $SiteServer / $SiteCode" -ForegroundColor Yellow 88 | } 89 | else { 90 | $res.psbase.Delete() 91 | Write-Host "deleted from sccm: $Computer" -ForegroundColor Green 92 | } 93 | } 94 | else { 95 | Write-Warning "$Computer not found in Configuration Manager site database" 96 | } 97 | } 98 | catch { 99 | Write-Error $_.Exception.Message 100 | } 101 | } 102 | } 103 | $time2 = Get-Date 104 | $tdiff = New-TimeSpan -Start $time1 -End $time2 105 | Write-Host "completed. runtime: $($tdiff.TotalSeconds) seconds" -ForegroundColor Cyan 106 | -------------------------------------------------------------------------------- /devices/Remove-CmClient.ps1: -------------------------------------------------------------------------------- 1 | #requires -RunAsAdministrator 2 | #requires -Version 3.0 3 | <# 4 | 1. SMS Agent Host Service 5 | 2. CCMSetup service (if present) 6 | 3. \windows\ccm directory 7 | 4. \windows\ccmsetup directory 8 | 5. \windows\ccmcache directory 9 | 6. \windows\smscfg.ini 10 | 7. \windows\sms*.mif (if present) 11 | 8. HKLM\software\Microsoft\ccm registry keys 12 | 9. HKLM\software\Microsoft\CCMSETUP registry keys 13 | 10. HKLM\software\Microsoft\SMS registry keys 14 | 11. root\cimv2\sms WMI namespace 15 | 12. root\ccm WMI namespace 16 | 13. In Task Scheduler library, under "Microsoft" delete the "Configuration Manager" folder and any tasks within it. 17 | 14. In the Machine Certificate store delete any certs under the SMS\certificates folder 18 | #> 19 | 20 | function Remove-CmClient { 21 | [CmdletBinding(SupportsShouldProcess=$True)] 22 | param () 23 | try { 24 | Write-Verbose "stopping ccmexec.exe process" 25 | Get-Process -Name "ccmexec.exe" | Stop-Process -Force -ErrorAction SilentlyContinue 26 | ('ccm','ccmsetup','ccmcache') | ForEach-Object { 27 | Write-Verbose "searching for folder: windows\$_" 28 | $fullpath = Join-Path -Path $env:SystemRoot -ChildPath $_ 29 | if (Test-Path $fullpath) { 30 | Write-Verbose "found. removing folder: $fullpath" 31 | Remove-Item -Path $fullpath -Filter "*.*" -Recurse -Force -ErrorAction SilentlyContinue 32 | } 33 | else { 34 | Write-Verbose "not found: $fullpath" 35 | } 36 | } 37 | Write-Verbose "searching for: windows\smscfg.ini" 38 | $smscfg = Join-Path -Path $env:SystemRoot -ChildPath "smscfg.ini" 39 | if (Test-Path $smscfg) { 40 | Write-Verbose "found. removing: windows\smscfg.ini" 41 | Remove-Item -Path $smscfg -Force -ErrorAction SilentlyContinue 42 | } 43 | else { 44 | Write-Verbose "smscfg.ini file not found" 45 | } 46 | Write-Verbose "searching for sms*.mif files in $env:SystemRoot" 47 | Get-ChildItem -Path $env:SystemRoot -Filter "sms*.mif" | Remove-Item -Force -ErrorAction SilentlyContinue 48 | Write-Verbose "searching for registry keys" 49 | ('HKLM:Software\Microsoft\ccm','HKLM:Software\Microsoft\ccmsetup','HKLM:Software\Microsoft\sms') | ForEach-Object { 50 | if (Test-Path -Path $_) { 51 | Write-Verbose "removing: $_" 52 | Remove-Item -Path $_ -Force -Recurse -ErrorAction SilentlyContinue 53 | } 54 | else { 55 | Write-Verbose "not found: $_" 56 | } 57 | } 58 | } 59 | catch { 60 | Write-Error $Error[0].Exception.Message 61 | } 62 | } -------------------------------------------------------------------------------- /devices/Set-CmClientSiteCode.ps1: -------------------------------------------------------------------------------- 1 | function Set-CmClientSiteCode { 2 | <# 3 | .DESCRIPTION 4 | Set CM client site code by auto-assignment or explicit value 5 | .PARAMETER SiteCode 6 | Site code text 7 | .EXAMPLE 8 | Set-CmClientSiteCode 9 | .EXAMPLE 10 | Set-CmClientSiteCode -SiteCode "ABC" 11 | .EXAMPLE 12 | Invoke-Command -ComputerName "client03" -File "c:\scripts\Set-CmClientSiteCode.ps1" 13 | #> 14 | [CmdletBinding()] 15 | param ( 16 | [parameter(Mandatory=$False)] 17 | [ValidateLength(0,3)] 18 | [string] $SiteCode = "" 19 | ) 20 | try { 21 | $sms = New-Object –COMObject "Microsoft.SMS.Client" 22 | $currentSiteCode = $sms.GetAssignedSite() 23 | Write-Host "current: $currentSiteCode" 24 | if ($SiteCode -ne "") { 25 | if ($currentSiteCode –ne $SiteCode) { $sms.SetAssignedSite($SiteCode) } 26 | } 27 | else { 28 | if ($currentSiteCode –ne $sms.AutoDiscoverSite() ) { $sms.SetAssignedSite($sms.AutoDiscoverSite()) } 29 | } 30 | $result = $sms.GetAssignedSite() 31 | } 32 | catch { 33 | Write-Error $Error[0].Exception.Message 34 | } 35 | finally { 36 | Write-Output $result 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /queries/AppInstalls-Top100.sql: -------------------------------------------------------------------------------- 1 | SELECT TOP 100 2 | ProductName0 AS ProductName, 3 | ProductVersion0 AS [Version], 4 | Publisher0 AS Publisher, 5 | COUNT(*) AS Clients 6 | FROM 7 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED 8 | GROUP BY 9 | ProductName0, 10 | ProductVersion0, 11 | Publisher0 12 | ORDER BY 13 | Clients DESC 14 | -------------------------------------------------------------------------------- /queries/Clients-BiosVersions.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | BIOSVersion0 AS BIOSVersion, 3 | InstallDate0 AS InstallDate, 4 | Version0 AS [Version], 5 | COUNT(*) AS Clients 6 | FROM 7 | dbo.v_GS_PC_BIOS 8 | GROUP BY 9 | BIOSVersion0, 10 | InstallDate0, 11 | Version0 12 | -------------------------------------------------------------------------------- /queries/Clients-Dell-D6000-Docks.sql: -------------------------------------------------------------------------------- 1 | /* 2 | select 3 | SMS_R_SYSTEM.ResourceID, 4 | SMS_R_SYSTEM.ResourceType, 5 | SMS_R_SYSTEM.Name, 6 | SMS_R_SYSTEM.SMSUniqueIdentifier, 7 | SMS_R_SYSTEM.ResourceDomainORWorkgroup, 8 | SMS_R_SYSTEM.Client 9 | from SMS_R_System 10 | inner join SMS_G_System_SYSTEM_DEVICES 11 | on SMS_G_System_SYSTEM_DEVICES.ResourceID = SMS_R_System.ResourceId 12 | where 13 | SMS_G_System_SYSTEM_DEVICES.Name in ("Dell Universal Dock D6000") order by SMS_R_System.Name 14 | */ 15 | select 16 | v_R_SYSTEM.ResourceID, 17 | v_R_SYSTEM.ResourceType, 18 | v_R_SYSTEM.Name0, 19 | from v_R_System 20 | inner join v_GS_SYSTEM_DEVICES 21 | on v_GS_SYSTEM_DEVICES.ResourceID = v_R_System.ResourceId 22 | where v_GS_SYSTEM_DEVICES.Name in ("Dell Universal Dock D6000") 23 | order by v_R_System.Name 24 | -------------------------------------------------------------------------------- /queries/Clients-DockModels.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_GS_SYSTEM_DEVICES.Name0 As DockModel, 3 | COUNT(*) as DockDevices 4 | FROM dbo.v_GS_SYSTEM_DEVICES 5 | GROUP BY Name0 6 | WHERE Name0 LIKE '%Dock%' 7 | ORDER BY DockDevices DESC 8 | -------------------------------------------------------------------------------- /queries/Clients-IPGateways.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | DefaultIPGateway0 AS Gateway, 3 | COUNT(*) AS Clients 4 | FROM 5 | dbo.v_GS_NETWORK_ADAPTER_CONFIGURATION 6 | GROUP BY 7 | DefaultIPGateway0 8 | ORDER BY 9 | DefaultIPGateway0 10 | -------------------------------------------------------------------------------- /queries/Clients-Inventory-All.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_R_System.Name0 AS ComputerName, 3 | dbo.v_R_System.AD_Site_Name0 AS ADSiteName, 4 | dbo.v_R_System.Client_Version0 AS ClientVersion, 5 | dbo.v_GS_LOGICAL_DISK.DeviceID0 AS DiskID, 6 | (dbo.v_GS_LOGICAL_DISK.Size0 / 1024.0) AS DiskSize, 7 | (dbo.v_GS_LOGICAL_DISK.FreeSpace0 / 1024.0) AS DiskFree, 8 | ROUND( (dbo.v_GS_LOGICAL_DISK.FreeSpace0 * 1.0 / dbo.v_GS_LOGICAL_DISK.Size0), 2) AS DiskUsed, 9 | dbo.v_GS_NETWORK_ADAPTER_CONFIGURATION.IPEnabled0 AS IPEnabled, 10 | dbo.v_GS_NETWORK_ADAPTER_CONFIGURATION.IPAddress0 AS IPAddress, 11 | dbo.v_GS_NETWORK_ADAPTER_CONFIGURATION.MACAddress0 AS MACAddress, 12 | dbo.v_GS_NETWORK_ADAPTER_CONFIGURATION.DefaultIPGateway0 AS IPGateway, 13 | dbo.v_GS_PROCESSOR.Name0 AS Processor, 14 | dbo.v_GS_X86_PC_MEMORY.TotalPhysicalMemory0 as Memory, 15 | dbo.vWorkstationStatus.OperatingSystem, 16 | dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 as OSBuild, 17 | dbo.v_GS_SYSTEM_ENCLOSURE.SerialNumber0 as SerialNum, 18 | dbo.vWorkstationStatus.LastHardwareScan, 19 | dbo.vWorkstationStatus.LastPolicyRequest, 20 | dbo.vWorkstationStatus.LastMPServerName 21 | FROM 22 | dbo.v_R_System INNER JOIN 23 | dbo.vWorkstationStatus ON 24 | dbo.v_R_System.ResourceID = dbo.vWorkstationStatus.ResourceID LEFT OUTER JOIN 25 | dbo.v_GS_PROCESSOR ON 26 | dbo.v_R_System.ResourceID = dbo.v_GS_PROCESSOR.ResourceID LEFT OUTER JOIN 27 | dbo.v_GS_NETWORK_ADAPTER_CONFIGURATION ON 28 | dbo.v_R_System.ResourceID = dbo.v_GS_NETWORK_ADAPTER_CONFIGURATION.ResourceID LEFT OUTER JOIN 29 | dbo.v_GS_LOGICAL_DISK ON 30 | dbo.v_R_System.ResourceID = dbo.v_GS_LOGICAL_DISK.ResourceID LEFT OUTER JOIN 31 | dbo.v_GS_OPERATING_SYSTEM ON 32 | dbo.v_R_System.ResourceID = dbo.v_GS_OPERATING_SYSTEM.ResourceID LEFT OUTER JOIN 33 | dbo.v_GS_X86_PC_MEMORY ON 34 | dbo.v_R_System.ResourceID = dbo.v_GS_X86_PC_MEMORY.ResourceID LEFT OUTER JOIN 35 | dbo.v_GS_SYSTEM_ENCLOSURE ON 36 | dbo.v_R_System.ResourceID = dbo.v_GS_SYSTEM_ENCLOSURE.ResourceID 37 | WHERE 38 | (dbo.v_GS_LOGICAL_DISK.DeviceID0 = N'C:') 39 | AND 40 | (dbo.v_GS_NETWORK_ADAPTER_CONFIGURATION.IPEnabled0 = 1) 41 | ORDER BY 42 | ComputerName 43 | -------------------------------------------------------------------------------- /queries/Clients-Inventory-General.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.vWorkstationStatus.Name, 3 | dbo.vWorkstationStatus.UserName, 4 | dbo.v_GS_OPERATING_SYSTEM.Caption0 AS OperatingSystem, 5 | CASE 6 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 10586) THEN '1511' 7 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 14393) THEN '1607' 8 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 15063) THEN '1703' 9 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 16299) THEN '1709' 10 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 17134) THEN '1803' 11 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 7601) THEN 'SP1' 12 | WHEN (dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 = 9600) THEN 'RTM' 13 | ELSE dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 14 | END AS OsBuild, 15 | dbo.vWorkstationStatus.SystemType, 16 | dbo.vWorkstationStatus.ClientVersion, 17 | dbo.vWorkstationStatus.UserDomain, 18 | CASE 19 | WHEN (dbo.vWorkstationStatus.IsVirtualMachine = 1) THEN 'Y' 20 | ELSE 'N' END AS IsVM, 21 | dbo.vWorkstationStatus.LastHealthEvaluationResult AS LastHealthEval, 22 | dbo.vWorkstationStatus.LastHardwareScan AS LastHwScan, 23 | dbo.vWorkstationStatus.LastDDR 24 | FROM 25 | dbo.vWorkstationStatus LEFT OUTER JOIN 26 | dbo.v_GS_OPERATING_SYSTEM ON dbo.vWorkstationStatus.ResourceID = dbo.v_GS_OPERATING_SYSTEM.ResourceID 27 | ORDER BY 28 | Name 29 | -------------------------------------------------------------------------------- /queries/Clients-Inventory-Models.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | Manufacturer0 AS Manufacturer, 3 | Model0 AS Model, 4 | COUNT(*) AS Clients 5 | FROM 6 | dbo.v_GS_COMPUTER_SYSTEM 7 | GROUP BY 8 | Manufacturer0, 9 | Model0 10 | ORDER BY 11 | Manufacturer0, 12 | Model0 13 | -------------------------------------------------------------------------------- /queries/Clients-Inventory-OsVersions.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | Caption0 AS OSName, 3 | BuildNumber0 AS OSBuild, 4 | CSDVersion0 AS SvcPack, 5 | OSArchitecture0 AS Arch, 6 | OSLanguage0 AS Lang, 7 | COUNT(*) AS Clients 8 | FROM 9 | dbo.v_GS_OPERATING_SYSTEM 10 | GROUP BY 11 | Caption0, 12 | BuildNumber0, 13 | CSDVersion0, 14 | OSArchitecture0, 15 | OSLanguage0 16 | ORDER BY 17 | Caption0, BuildNumber0 18 | -------------------------------------------------------------------------------- /queries/Clients-OldHwInventory.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_R_System.Name0 AS Computer, 3 | dbo.v_GS_OPERATING_SYSTEM.Caption0 AS OSVersion, 4 | dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 AS Build, 5 | dbo.v_GS_OPERATING_SYSTEM.OSArchitecture0 AS [Platform], 6 | dbo.vWorkstationStatus.LastHardwareScan AS LastHWScan, 7 | dbo.vWorkstationStatus.ClientVersion, 8 | dbo.vWorkstationStatus.LastMPServerName AS LastMP, 9 | dbo.vWorkstationStatus.LastDDR, 10 | dbo.vWorkstationStatus.LastHealthEvaluationResult 11 | FROM 12 | dbo.v_R_System INNER JOIN 13 | dbo.v_GS_OPERATING_SYSTEM ON dbo.v_GS_OPERATING_SYSTEM.ResourceID = dbo.v_R_System.ResourceID LEFT OUTER JOIN 14 | dbo.vWorkstationStatus ON dbo.v_R_System.ResourceID = dbo.vWorkstationStatus.ResourceID 15 | WHERE 16 | (dbo.v_GS_OPERATING_SYSTEM.OSArchitecture0 IS NULL) 17 | OR 18 | (DATEDIFF(dd,GETDATE(),dbo.vWorkstationStatus.LastHardwareScan) >= 14) 19 | ORDER BY 20 | dbo.v_R_System.Name0 21 | -------------------------------------------------------------------------------- /queries/Clients-Summary.sql: -------------------------------------------------------------------------------- 1 | select distinct 2 | Name0 as ComputerName, 3 | ResourceID, 4 | Client0 as Client, 5 | Client_Version0 as ClientVersion, 6 | AD_Site_Name0 as ADSiteName, 7 | Operating_System_Name_and0 AS OS, 8 | case 9 | when (Operating_System_Name_and0 like '%workstation%') then 'Workstation' 10 | when (Operating_System_Name_and0 like '%server%') then 'Server' 11 | else 'Other' end as OSType 12 | from 13 | v_R_System 14 | order by 15 | Name0 16 | -------------------------------------------------------------------------------- /queries/Clients-TPMStatus.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | CASE 3 | WHEN (IsActivated_InitialValue0 = 1) THEN 'YES' 4 | ELSE 'NO' END AS [Activated], 5 | CASE 6 | WHEN (IsEnabled_InitialValue0 = 1) THEN 'YES' 7 | ELSE 'NO' END AS [Enabled], 8 | CASE 9 | WHEN (IsOwned_InitialValue0 = 1) THEN 'YES' 10 | ELSE 'NO' END AS [Owned], 11 | COUNT(*) AS Clients 12 | FROM 13 | dbo.v_GS_TPM 14 | GROUP BY 15 | IsActivated_InitialValue0, 16 | IsEnabled_InitialValue0, 17 | IsOwned_InitialValue0 18 | -------------------------------------------------------------------------------- /queries/Clients-TopUsers.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | TOP 100 3 | UserName0 AS UserName, 4 | COUNT(*) AS Clients 5 | FROM 6 | dbo.v_GS_COMPUTER_SYSTEM 7 | GROUP BY 8 | UserName0 9 | ORDER BY 10 | Clients DESC 11 | -------------------------------------------------------------------------------- /queries/Clients-TotalMemory.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | TotalPhysicalMemory0 AS TotalMemory, 3 | COUNT(*) AS Clients 4 | FROM 5 | dbo.v_GS_X86_PC_MEMORY 6 | GROUP BY 7 | TotalPhysicalMemory0 8 | ORDER BY 9 | TotalPhysicalMemory0 10 | -------------------------------------------------------------------------------- /queries/Clients-WuVersions.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | Version0 AS [Version], 3 | COUNT(*) AS Clients 4 | FROM 5 | dbo.v_GS_WINDOWSUPDATEAGENTVERSION 6 | GROUP BY 7 | Version0 8 | ORDER BY 9 | [Version] 10 | -------------------------------------------------------------------------------- /queries/Computers-ADSites.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | COALESCE(AD_Site_Name0, 'Default') AS ADSite, 3 | COUNT(*) AS Computers 4 | FROM 5 | dbo.v_R_System 6 | GROUP BY 7 | AD_SITE_Name0 8 | ORDER BY 9 | ADSite 10 | -------------------------------------------------------------------------------- /queries/Run-Query.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [parameter()][string]$Path = $PSScriptRoot 4 | ) 5 | if (!(Get-Module dbatools -ListAvailable)) { 6 | Install-Module dbatools -Scope CurrentUser -Force 7 | } 8 | $queryFiles = Get-ChildItem -Path $Path -Filter "*.sql" 9 | if ($queryFiles.Count -gt 0) { 10 | $queryFile = $queryFiles | Select-Object Name,FullName | Out-GridView -Title "Select Query to Run" -OutputMode Single 11 | if ($queryFile) { 12 | $query = Get-Content $queryFile.FullName 13 | Invoke-DbaQuery -SqlInstance $SqlInstance -Query $query 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /queries/Site-DPServers.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | [ServerName], 3 | [SMSSiteCode] AS SiteCode, 4 | [IsPeerDP], 5 | [IsPullDP], 6 | [IsFileStreaming], 7 | [IsBITS], 8 | [IsMulticast], 9 | [IsProtected], 10 | [IsPXE], 11 | [IsActive], 12 | [AnonymousEnabled] AS [Anon], 13 | [SslState] AS [SSL], 14 | [PreStagingAllowed] AS [PreStage], 15 | [MinFreeSpace], 16 | [RemoveWDS], 17 | [ResponseDelay], 18 | [SupportUnknownMachines] AS [AllowUnknowns], 19 | [TransferRate], 20 | [Description] 21 | FROM 22 | dbo.vDistributionPoints 23 | ORDER BY 24 | ServerName 25 | -------------------------------------------------------------------------------- /queries/Site-DPStatus.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_DistributionPoints.ServerName, 3 | dbo.v_DistributionPoints.SMSSiteCode AS SiteCode, 4 | CASE 5 | WHEN (dbo.v_DistributionPoints.SslState = 1) THEN 'Y' 6 | ELSE 'N' END AS IsSSL, 7 | CASE 8 | WHEN (dbo.v_DistributionPoints.PreStagingAllowed = 1) THEN 'Y' 9 | ELSE 'N' END AS IsPreStage, 10 | CASE 11 | WHEN (dbo.v_DistributionPoints.IsPXE = 1) THEN 'Y' 12 | ELSE 'N' END AS IsPXE, 13 | dbo.v_ContentDistributionReport_DP.PkgCount AS Packages, 14 | dbo.v_ContentDistributionReport_DP.NumberInstalled AS Success, 15 | dbo.v_ContentDistributionReport_DP.NumberInProgress AS Pending, 16 | dbo.v_ContentDistributionReport_DP.NumberErrors AS Failed 17 | FROM 18 | dbo.v_DistributionPoints INNER JOIN 19 | dbo.v_ContentDistributionReport_DP ON 20 | dbo.v_DistributionPoints.NALPath = dbo.v_ContentDistributionReport_DP.DPNALPath 21 | GROUP BY 22 | dbo.v_DistributionPoints.ServerName, 23 | dbo.v_DistributionPoints.SMSSiteCode, 24 | dbo.v_DistributionPoints.SslState, 25 | dbo.v_DistributionPoints.PreStagingAllowed, 26 | dbo.v_DistributionPoints.IsPXE, 27 | dbo.v_ContentDistributionReport_DP.PkgCount, 28 | dbo.v_ContentDistributionReport_DP.NumberInstalled, 29 | dbo.v_ContentDistributionReport_DP.NumberInProgress, 30 | dbo.v_ContentDistributionReport_DP.NumberErrors 31 | ORDER BY 32 | dbo.v_DistributionPoints.ServerName 33 | -------------------------------------------------------------------------------- /queries/Software-Deployments-Summary.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | SoftwareName AS Software, 3 | CollectionName AS Collection, 4 | DeploymentTime, 5 | NumberTotal AS NumTotal, 6 | NumberSuccess AS NumSuccess, 7 | NumberErrors AS NumFailed, 8 | NumberInProgress AS NumPending, 9 | NumberUnknown AS NumUnknown, 10 | NumberOther AS NumOther, 11 | ProgramName, 12 | PackageID 13 | FROM 14 | dbo.v_DeploymentSummary 15 | WHERE 16 | (PackageID IS NOT NULL) AND (PackageID <> '') 17 | ORDER BY 18 | Software 19 | -------------------------------------------------------------------------------- /queries/Software-Google-BackupSync.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_R_System.Name0 AS ComputerName, 3 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ResourceID, 4 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 AS ProductName, 5 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ARPDisplayName0 AS DisplayName, 6 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductVersion0 AS Version, 7 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.Publisher0 AS Publisher, 8 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductCode0 AS ProductCode 9 | FROM 10 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED INNER JOIN 11 | dbo.v_R_System ON dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ResourceID = dbo.v_R_System.ResourceID 12 | WHERE 13 | (dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 = 'Backup and Sync from Google') 14 | ORDER BY 15 | ComputerName 16 | -------------------------------------------------------------------------------- /queries/Software-Google-Chrome.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_R_System.Name0 AS ComputerName, 3 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ResourceID, 4 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 AS ProductName, 5 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ARPDisplayName0 AS DisplayName, 6 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductVersion0 AS Version, 7 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.Publisher0 AS Publisher, 8 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductCode0 AS ProductCode 9 | FROM 10 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED INNER JOIN 11 | dbo.v_R_System ON dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ResourceID = dbo.v_R_System.ResourceID 12 | WHERE 13 | (dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 LIKE 'Google Chrome%') 14 | ORDER BY 15 | ComputerName 16 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-AllVersions.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | SYS.Name0 AS ComputerName, 3 | ARP.DisplayName0 As [ProductName], 4 | ARP.Version0 As [Version], 5 | ARP.InstallDate0 As [InstallDate] 6 | FROM 7 | dbo.v_R_System As SYS 8 | INNER JOIN dbo.v_FullCollectionMembership FCM On FCM.ResourceID = SYS.ResourceID 9 | INNER JOIN dbo.v_Add_REMOVE_PROGRAMS As ARP On SYS.ResourceID = ARP.ResourceID 10 | WHERE 11 | (ARP.DisplayName0 LIKE '%Microsoft % Standard%' 12 | OR ARP.DisplayName0 LIKE 'Microsoft % Professional%' 13 | OR ARP.DisplayName0 LIKE 'Microsoft % Enterprise %') 14 | ORDER BY 15 | Name0 ASC 16 | -- https://prajwaldesai.com/sccm-sql-query-for-microsoft-office-32-bit-and-64-bit/ 17 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-Detailed.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_R_System.Name0 AS Computer, 3 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 AS ProductName, 4 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductVersion0 AS Version, 5 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.InstalledLocation0 AS InstallPath, 6 | CASE 7 | WHEN (RTRIM(ProductVersion0) = '16.0.9126.2282') THEN 'S1803 09' 8 | WHEN (RTRIM(ProductVersion0) = '16.0.9126.2275') THEN 'S1803 07' 9 | WHEN (RTRIM(ProductVersion0) = '16.0.9001.2171') THEN 'M1801 02' 10 | WHEN (RTRIM(ProductVersion0) = '16.0.9126.2259') THEN 'S1803 08' 11 | WHEN (RTRIM(ProductVersion0) = '16.0.10730.20102') THEN 'M1808 09' 12 | WHEN (RTRIM(ProductVersion0) = '16.0.10730.20138') THEN 'M1809 09' 13 | WHEN (RTRIM(ProductVersion0) = '16.0.10730.20127') THEN 'M1808 08' 14 | WHEN (RTRIM(ProductVersion0) = '16.0.10325.20082') THEN 'M1807 07' 15 | WHEN (RTRIM(ProductVersion0) = '16.0.10827.20138') THEN 'M1809 09' 16 | ELSE '' END AS Build, 17 | CASE 18 | WHEN (v_GS_INSTALLED_SOFTWARE_CATEGORIZED.InstalledLocation0 LIKE '%x86%') THEN '32' 19 | ELSE '64' END AS Pkg 20 | FROM 21 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED INNER JOIN 22 | dbo.v_R_System ON dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ResourceID = dbo.v_R_System.ResourceID 23 | WHERE 24 | (dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 IN 25 | ('Microsoft Office 365 ProPlus - en-us', 26 | 'Microsoft Project Standard 2016 - en-us', 27 | 'Microsoft Project Professional 2016 - en-us', 28 | 'Microsoft Visio Standard 2016 - en-us', 29 | 'Microsoft Visio Professional 2016 - en-us') 30 | ) 31 | ORDER BY 32 | Computer, 33 | ProductName 34 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-Detailed2.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | SYS.Name0 AS ComputerName, 3 | ARP.DisplayName0 AS ProductName, 4 | ARP.Version0 AS Version, 5 | dbo.v_GS_OPERATING_SYSTEM.Caption0 AS OperatingSystem, 6 | dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 AS Build, 7 | SYS.User_Name0 AS LastUser, 8 | dbo.v_R_User.User_Name0 AS MainUser, 9 | SYS.AD_Site_Name0 AS ADSite 10 | FROM 11 | dbo.v_R_User INNER JOIN 12 | dbo.v_UsersPrimaryMachines ON 13 | dbo.v_R_User.ResourceID = dbo.v_UsersPrimaryMachines.UserResourceID 14 | RIGHT OUTER JOIN 15 | dbo.v_R_System AS SYS INNER JOIN 16 | dbo.v_FullCollectionMembership AS FCM ON FCM.ResourceID = SYS.ResourceID INNER JOIN 17 | dbo.v_Add_Remove_Programs AS ARP ON 18 | SYS.ResourceID = ARP.ResourceID ON 19 | dbo.v_UsersPrimaryMachines.MachineID = SYS.ResourceID LEFT OUTER JOIN 20 | dbo.v_GS_OPERATING_SYSTEM ON SYS.ResourceID = dbo.v_GS_OPERATING_SYSTEM.ResourceID 21 | WHERE 22 | (ARP.DisplayName0 LIKE '%Microsoft % Standard%') OR 23 | (ARP.DisplayName0 LIKE 'Microsoft % Professional%') OR 24 | (ARP.DisplayName0 LIKE 'Microsoft % Enterprise %') OR 25 | (ARP.DisplayName0 = 'Microsoft Office 365 ProPlus - en-us') 26 | ORDER BY 27 | ComputerName 28 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-PlatformVersion.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | VersionToReport0 AS [Version], 3 | Platform0 AS [Platform], 4 | COUNT(*) AS Installs 5 | FROM 6 | dbo.v_GS_OFFICE365PROPLUSCONFIGURATIONS 7 | GROUP BY 8 | VersionToReport0, 9 | Platform0 10 | ORDER BY 11 | VersionToReport0 12 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-Project.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | SYS.Name0 AS ComputerName, 3 | ARP.DisplayName0 AS ProductName, 4 | ARP.Version0 AS Version, 5 | ARP.InstallDate0 AS InstallDate, 6 | SYS.AD_Site_Name0 AS ADSite, 7 | dbo.v_GS_COMPUTER_SYSTEM.Model0 AS Model, 8 | dbo.v_GS_OPERATING_SYSTEM.Caption0 AS OSName, 9 | dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 AS OSBuild, 10 | dbo.v_GS_PHYSICAL_MEMORY.Capacity0 AS Memory 11 | FROM 12 | dbo.v_R_System AS SYS INNER JOIN 13 | dbo.v_FullCollectionMembership AS FCM ON FCM.ResourceID = SYS.ResourceID INNER JOIN 14 | dbo.v_Add_Remove_Programs AS ARP ON SYS.ResourceID = ARP.ResourceID INNER JOIN 15 | dbo.v_GS_COMPUTER_SYSTEM ON SYS.ResourceID = dbo.v_GS_COMPUTER_SYSTEM.ResourceID INNER JOIN 16 | dbo.v_GS_OPERATING_SYSTEM ON SYS.ResourceID = dbo.v_GS_OPERATING_SYSTEM.ResourceID INNER JOIN 17 | dbo.v_GS_PHYSICAL_MEMORY ON SYS.ResourceID = dbo.v_GS_PHYSICAL_MEMORY.ResourceID 18 | WHERE 19 | (ARP.DisplayName0 LIKE '%Project Standard%' 20 | OR 21 | ARP.DisplayName0 LIKE '%Project Professional%' 22 | ) 23 | AND 24 | (ARP.InstallDate0 IS NOT NULL) 25 | ORDER BY 26 | ProductName, Version 27 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-Summary.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0, 3 | COUNT(*) AS Installs 4 | FROM 5 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED 6 | WHERE 7 | (dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 IN 8 | ('Microsoft Office 365 ProPlus - en-us', 9 | 'Microsoft Project Standard 2016 - en-us', 10 | 'Microsoft Project Professional 2016 - en-us', 11 | 'Microsoft Visio Standard 2016 - en-us', 12 | 'Microsoft Visio Professional 2016 - en-us') 13 | ) 14 | GROUP BY ProductName0 15 | ORDER BY ProductName0 16 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-VersionCounts.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT T1.ProductName, T1.Version, COUNT(*) AS QTY 2 | FROM ( 3 | SELECT DISTINCT 4 | SYS.Name0 AS ComputerName, 5 | ARP.DisplayName0 AS ProductName, 6 | ARP.Version0 AS [Version], 7 | ARP.InstallDate0 AS InstallDate 8 | FROM 9 | dbo.v_R_System AS SYS INNER JOIN 10 | dbo.v_FullCollectionMembership AS FCM ON FCM.ResourceID = SYS.ResourceID INNER JOIN 11 | dbo.v_Add_Remove_Programs AS ARP ON SYS.ResourceID = ARP.ResourceID 12 | WHERE 13 | ( 14 | (ARP.DisplayName0 LIKE '%Microsoft % Standard%') OR 15 | (ARP.DisplayName0 LIKE 'Microsoft % Professional%') OR 16 | (ARP.DisplayName0 LIKE 'Microsoft % Enterprise %') OR 17 | (ARP.DisplayName0 = 'Microsoft Office 365 ProPlus - en-us') 18 | ) 19 | ) AS T1 20 | GROUP BY 21 | ProductName, Version 22 | ORDER BY 23 | ProductName, Version 24 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-Versions.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0, 3 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductVersion0, 4 | CASE 5 | WHEN (RTRIM(ProductVersion0)='16.0.9126.2282') THEN 'S1803 09' 6 | WHEN (RTRIM(ProductVersion0)='16.0.9126.2275') THEN 'S1803 07' 7 | WHEN (RTRIM(ProductVersion0)='16.0.9001.2171') THEN 'M1801 02' 8 | WHEN (RTRIM(ProductVersion0)='16.0.9126.2259') THEN 'S1803 08' 9 | WHEN (RTRIM(ProductVersion0)='16.0.10730.20102') THEN 'M1808 09' 10 | WHEN (RTRIM(ProductVersion0)='16.0.10730.20138') THEN 'M1809 09' 11 | WHEN (RTRIM(ProductVersion0)='16.0.10730.20127') THEN 'M1808 08' 12 | WHEN (RTRIM(ProductVersion0)='16.0.10325.20082') THEN 'M1807 07' 13 | WHEN (RTRIM(ProductVersion0)='16.0.10827.20138') THEN 'M1809 09' 14 | ELSE '' END AS Build, 15 | COUNT(*) AS Installs 16 | FROM 17 | dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED 18 | WHERE 19 | (dbo.v_GS_INSTALLED_SOFTWARE_CATEGORIZED.ProductName0 IN 20 | ('Microsoft Office 365 ProPlus - en-us', 21 | 'Microsoft Project Standard 2016 - en-us', 22 | 'Microsoft Project Professional 2016 - en-us', 23 | 'Microsoft Visio Standard 2016 - en-us', 24 | 'Microsoft Visio Professional 2016 - en-us') 25 | ) 26 | GROUP BY ProductName0, ProductVersion0 27 | ORDER BY ProductName0 28 | -------------------------------------------------------------------------------- /queries/Software-OfficeProducts-Visio.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | SYS.Name0 AS ComputerName, 3 | ARP.DisplayName0 AS ProductName, 4 | ARP.Version0 AS Version, 5 | ARP.InstallDate0 AS InstallDate, 6 | SYS.AD_Site_Name0 AS ADSite, 7 | dbo.v_GS_COMPUTER_SYSTEM.Model0 AS Model, 8 | dbo.v_GS_OPERATING_SYSTEM.Caption0 AS OSName, 9 | dbo.v_GS_OPERATING_SYSTEM.BuildNumber0 AS OSBuild, 10 | dbo.v_GS_PHYSICAL_MEMORY.Capacity0 AS Memory 11 | FROM 12 | dbo.v_R_System AS SYS INNER JOIN 13 | dbo.v_FullCollectionMembership AS FCM ON FCM.ResourceID = SYS.ResourceID INNER JOIN 14 | dbo.v_Add_Remove_Programs AS ARP ON SYS.ResourceID = ARP.ResourceID INNER JOIN 15 | dbo.v_GS_COMPUTER_SYSTEM ON SYS.ResourceID = dbo.v_GS_COMPUTER_SYSTEM.ResourceID INNER JOIN 16 | dbo.v_GS_OPERATING_SYSTEM ON SYS.ResourceID = dbo.v_GS_OPERATING_SYSTEM.ResourceID INNER JOIN 17 | dbo.v_GS_PHYSICAL_MEMORY ON SYS.ResourceID = dbo.v_GS_PHYSICAL_MEMORY.ResourceID 18 | WHERE 19 | (ARP.DisplayName0 LIKE '%Visio Standard%' 20 | OR 21 | ARP.DisplayName0 LIKE '%Visio Professional%' 22 | ) 23 | AND 24 | (ARP.InstallDate0 IS NOT NULL) 25 | ORDER BY 26 | ProductName, Version 27 | -------------------------------------------------------------------------------- /queries/Software-OneDrive-Detailed.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_R_System.Name0 AS Computer, 3 | dbo.v_GS_INSTALLED_EXECUTABLE.ResourceID, 4 | dbo.v_GS_INSTALLED_EXECUTABLE.ExecutableName0 AS ExeName, 5 | dbo.v_GS_INSTALLED_EXECUTABLE.FileSize0 AS FileSize, 6 | dbo.v_GS_INSTALLED_EXECUTABLE.FileVersion0 AS FileVersion, 7 | dbo.v_GS_INSTALLED_EXECUTABLE.InstalledFilePath0 AS InstallPath, 8 | dbo.v_GS_INSTALLED_EXECUTABLE.ProductCode0 AS ProductCode, 9 | dbo.v_GS_INSTALLED_EXECUTABLE.ProductVersion0 AS ProductVersion, 10 | dbo.v_GS_INSTALLED_EXECUTABLE.Publisher0 AS Publisher 11 | FROM 12 | dbo.v_GS_INSTALLED_EXECUTABLE INNER JOIN 13 | dbo.v_R_System ON dbo.v_GS_INSTALLED_EXECUTABLE.ResourceID = dbo.v_R_System.ResourceID 14 | WHERE 15 | (dbo.v_GS_INSTALLED_EXECUTABLE.ExecutableName0 IN ('OneDrive.exe', 'Groove.exe')) 16 | ORDER BY 17 | Computer 18 | -------------------------------------------------------------------------------- /queries/Software-OneDrive-Totals.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_GS_SoftwareFile.FileName, 3 | dbo.v_GS_SoftwareFile.FileVersion, 4 | COUNT(*) AS Installs 5 | FROM 6 | dbo.v_GS_SoftwareFile 7 | WHERE 8 | (dbo.v_GS_SoftwareFile.FileName = 'OneDrive.exe') 9 | GROUP BY 10 | dbo.v_GS_SoftwareFile.FileName, 11 | dbo.v_GS_SoftwareFile.FileVersion 12 | ORDER BY 13 | dbo.v_GS_SoftwareFile.FileVersion 14 | -------------------------------------------------------------------------------- /queries/Software-SQLExpress-Counts.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | ProductName0 as ProductName, 3 | ProductVersion0 as Version, 4 | Publisher0 as Publisher, 5 | case 6 | when (ProductVersion0 like '9.%') then 'UNSUPPORTED' 7 | when (ProductVersion0 like '10.%') then 'EOL 2019/07/09' 8 | else 'SUPPORTED' end as Support, 9 | COUNT(*) AS Installs 10 | FROM 11 | v_GS_INSTALLED_SOFTWARE_CATEGORIZED 12 | WHERE 13 | ProductName0 LIKE 'Microsoft SQL Server % Express%' 14 | GROUP BY 15 | ProductName0, ProductVersion0, Publisher0 16 | ORDER BY 17 | ProductName0 18 | -------------------------------------------------------------------------------- /queries/Software-Symantec-NoDiskEncryption.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | MachineID, 3 | Name, 4 | DeviceOS, 5 | DeviceOSBuild, 6 | PrimaryUser, 7 | ClientVersion 8 | FROM v_CombinedDeviceResources 9 | WHERE 10 | Name NOT IN ('x86 Unknown Computer (x86 Unknown Computer)','x64 Unknown Computer (x64 Unknown Computer)','Provisioning Device (Provisioning Device)') 11 | AND 12 | MachineID NOT IN ( 13 | select distinct ResourceID 14 | from v_GS_INSTALLED_SOFTWARE_CATEGORIZED 15 | where ProductName0 = 'Symantec Encryption Desktop' 16 | ) 17 | ORDER BY Name 18 | -------------------------------------------------------------------------------- /queries/Users-Machine-Logins.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_R_System.Name0 AS ComputerName, 3 | dbo.v_GS_USER_PROFILE.LocalPath0 AS ProfilePath, 4 | dbo.v_GS_USER_PROFILE.ResourceID, 5 | dbo.v_GS_USER_PROFILE.TimeStamp, 6 | dbo.v_GS_USER_PROFILE.SID0 AS UserSID, 7 | dbo.v_R_System.AD_Site_Name0 AS ADSite 8 | FROM 9 | dbo.v_GS_USER_PROFILE INNER JOIN 10 | dbo.v_R_User ON dbo.v_GS_USER_PROFILE.SID0 = dbo.v_R_User.SID0 INNER JOIN 11 | dbo.v_R_System ON dbo.v_GS_USER_PROFILE.ResourceID = dbo.v_R_System.ResourceID 12 | WHERE 13 | (dbo.v_R_User.Unique_User_Name0 = N'CONTOSO\sccmadmin') 14 | ORDER BY ComputerName 15 | -------------------------------------------------------------------------------- /queries/Users.sql: -------------------------------------------------------------------------------- 1 | SELECT DISTINCT 2 | dbo.v_R_User.Full_User_Name0 AS FullName, 3 | dbo.v_R_User.Unique_User_Name0 AS UserName, 4 | dbo.v_R_User.Windows_NT_Domain0 AS UserDomain, 5 | dbo.v_R_User.ResourceID, dbo.v_R_User.department, 6 | dbo.v_R_User.title, 7 | dbo.v_R_User.User_Principal_Name0 AS UPN, 8 | dbo.v_R_User.Distinguished_Name0 AS UserDN, 9 | dbo.v_R_User.SID0 AS SID, 10 | u2.Unique_User_Name0 AS Mgr 11 | FROM 12 | dbo.v_R_User LEFT OUTER JOIN 13 | dbo.v_R_User AS u2 ON dbo.v_R_User.manager = u2.Distinguished_Name0 14 | -------------------------------------------------------------------------------- /queries/queries.txt: -------------------------------------------------------------------------------- 1 | Clients-BiosVersions 2 | Clients-IPGateways 3 | Clients-Inventory-All 4 | Clients-Inventory-General 5 | Clients-Inventory-Models 6 | Clients-Inventory-OsVersions 7 | Clients-OldHwInventory 8 | Clients-Summary 9 | Clients-TPMStatus 10 | Clients-TopUsers 11 | Clients-TotalMemory 12 | Clients-WuVersions 13 | Computers-ADSites 14 | Site-DPServers 15 | Site-DPStatus 16 | Software-Deployments-Summary 17 | Software-Google-BackupSync 18 | Software-Google-Chrome 19 | Software-OfficeProducts-AllVersions 20 | Software-OfficeProducts-Detailed 21 | Software-OfficeProducts-Detailed2 22 | Software-OfficeProducts-PlatformVersion 23 | Software-OfficeProducts-Project 24 | Software-OfficeProducts-Summary 25 | Software-OfficeProducts-VersionCounts 26 | Software-OfficeProducts-Versions 27 | Software-OfficeProducts-Visio 28 | Software-OneDrive-Detailed 29 | Software-OneDrive-Totals 30 | Users-Machine-Logins 31 | Users 32 | -------------------------------------------------------------------------------- /site/Disable-IPv6.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(SupportsShouldProcess)] 2 | Get-NetAdapterBinding | 3 | Where-Object {($_.ElementName -eq 'ms_tcpip6') -and ($_.Enabled -eq $True)} | 4 | Disable-NetAdapterBinding -ComponentID ms_tcpip6 5 | -------------------------------------------------------------------------------- /site/Export-CmHwInventoryClasses.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .NOTES 3 | 4 | adapted from: https://blogs.technet.microsoft.com/cmpfekevin/2018/04/05/configmgr-exportimport-hardware-inventory-classes/ 5 | 6 | #> 7 | 8 | function Export-CmHwInventoryClasses { 9 | [cmdletbinding()] 10 | param( 11 | [parameter(Mandatory=$true)] 12 | [ValidatePattern('.*(.xml)')] 13 | [String] $XMLFile, 14 | [switch] $Import, 15 | [parameter(Mandatory=$true)] 16 | [string] $SiteCode, 17 | [parameter(Mandatory=$true)] 18 | [string] $CMProvider = "." 19 | ) 20 | 21 | $CIMProps = @{ 22 | ComputerName = $CMProvider 23 | Namespace = "root\sms\site_$($SiteCode)" 24 | } 25 | 26 | $TodaysDate = get-date -Format "yyyy-MM-dd-HHmmss" 27 | 28 | $ExportClientHardwareInventoryClasses = { 29 | $File = $XMLFile -split '.xml' 30 | $File = "$($XMLFile)-$($TodaysDate).xml" 31 | $ExportHWInvClasses = @() 32 | $ClientSettings = Get-CimInstance @CIMProps -ClassName SMS_ClientSettings | Get-CimInstance 33 | $DefaultClientSettings = Get-CimInstance @CIMProps -ClassName SMS_ClientSettingsDefault | Get-CimInstance 34 | $DefaultClientSettings | Add-Member -NotePropertyName AgentConfigurations -NotePropertyValue @{} 35 | $DefaultClientSettings.AgentConfigurations.Add('AgentID',15) 36 | $DefaultClientSettings.AgentConfigurations.Add('InventoryReportID','{00000000-0000-0000-0000-000000000001}') 37 | $ClientSettings += $DefaultClientSettings 38 | Foreach ($ClientSetting in $ClientSettings) { 39 | if ($HWInvSetting = $ClientSetting.AgentConfigurations | where {$_.AgentID -eq 15}) { 40 | write-verbose $HWInvSetting.InventoryReportID 41 | $HWInvDetails = @{ 42 | ClientSetting = $ClientSetting 43 | AgentConfiguration = $HWInvSetting 44 | InventoryReport = Get-CimInstance @CIMProps -ClassName SMS_InventoryReport -Filter ('InventoryReportID = "' + $HWInvSetting.InventoryReportID + '"') | Get-CimInstance 45 | } 46 | $ExportHWInvClasses += $HWInvDetails 47 | } 48 | } 49 | Export-Clixml -InputObject $ExportHWInvClasses -Path $File 50 | } 51 | 52 | $ImportClientHardwareInventoryClasses = { 53 | $ImportedHWInvClasses = Import-Clixml $XMLFile 54 | foreach ($ClientSetting in $ImportedHWInvClasses) { 55 | $InventoryReport = Get-CimInstance @CIMProps -ClassName SMS_InventoryReport -Filter ('InventoryReportID = "'+ $ClientSetting.InventoryReport.InventoryReportID + '"') | Get-CimInstance 56 | $InventoryReport.ReportClasses = $ClientSetting.InventoryReport.ReportClasses 57 | $InventoryReport | Set-CimInstance 58 | } 59 | } 60 | 61 | If ($Import) { 62 | Invoke-Command $ImportClientHardwareInventoryClasses 63 | } else { 64 | Invoke-Command $ExportClientHardwareInventoryClasses 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /site/Get-CmFullVersionName.ps1: -------------------------------------------------------------------------------- 1 | function Get-CmFullVersionName { 2 | <# 3 | .SYNOPSIS 4 | Get ConfigMgr Version Name from Build Number 5 | .DESCRIPTION 6 | Returns full ConfigMgr version name from Build Number string 7 | .PARAMETER BuildNumber 8 | Version build number, such as '5.0.8540.1611' 9 | .EXAMPLE 10 | Get-CmFullVersionName -BuildNumber '5.0.8540.1611' 11 | Returns: "SCCM 1706 - Update to Rollup 1 (KB4042949)" 12 | .NOTES 13 | Ugly AF and Crude, but usually works okay 14 | Thanks to System Center Dudes web site for the published data table 15 | .OUTPUT 16 | String containing full version name, or $null if no match 17 | #> 18 | [CmdletBinding()] 19 | param ( 20 | [parameter(Mandatory=$True, ValueFromPipeline=$True, HelpMessage="ConfigMgr Build Number")] 21 | [ValidateNotNullOrEmpty()] 22 | [string] $BuildNumber 23 | ) 24 | $uri = 'https://www.systemcenterdudes.com/sccm-2012-version-numbers/' 25 | try { 26 | Write-Verbose "Reading: $uri" 27 | $raw = (New-Object System.Net.WebClient).DownloadString($uri) 28 | Write-Verbose "HTML data source imported successfully" 29 | } 30 | catch { 31 | Write-Error $_.Exception.HelpMessage 32 | break 33 | } 34 | $raw = $raw.Replace("`n"," ") 35 | # get rough starting point to snatch table data 36 | $start = $raw.IndexOf('class="tablepress tablepress-id-1">') 37 | $content = $raw.Substring($start+42) 38 | # get ending point to trim off excess trailing data 39 | $end = $content.IndexOf('') 40 | # trim data to get just the desired table, oh, that big juicy table 41 | $content = $content.Substring(0, $end) 42 | $data = $content -replace "","" 43 | $data = $data -replace "","" 44 | $data = $data -split "td class" 45 | # you're probably laughing right about here, but that's okay 46 | foreach ($row in $data) { 47 | if ($row.StartsWith('="column-1"')) { 48 | $name = ($row.Substring(12)) -replace '<', '' 49 | } 50 | elseif ($row.StartsWith('="column-2"')) { 51 | $ver = ($row.Substring(12)) -replace '<', '' 52 | } 53 | # okay, by now, you're probably angry, that's okay too 54 | Write-Verbose "NAME: $name // VERSION: $ver" 55 | if ($BuildNumber -eq $ver) { 56 | Write-Output $name 57 | break 58 | } 59 | } 60 | # phew! you made it! 61 | } 62 | -------------------------------------------------------------------------------- /site/Get-CmHwInvClasses.ps1: -------------------------------------------------------------------------------- 1 | Import-Module dbatools 2 | 3 | function Get-CmHwInvClasses { 4 | [CmdletBinding()] 5 | param ( 6 | [parameter(Mandatory=$True)] 7 | [ValidateNotNullOrEmpty()] 8 | [string] $SQLServerName, 9 | [parameter(Mandatory=$True)] 10 | [ValidateLength(3,3)] 11 | [string] $SiteCode 12 | ) 13 | $output = "" 14 | try { 15 | $query = "SELECT DISTINCT irc.ClassName, irc.PropertyName, irc.SMSClassID, 16 | CASE WHEN (cip.SettingName IS NOT NULL) THEN cip.SettingName 17 | ELSE 'Default Client Settings' 18 | END AS 'SettingName', 19 | CASE WHEN cip.CollectionID IS NOT NULL THEN cip.CollectionID 20 | ELSE 'SMS00001' END AS 'CollectionID' 21 | FROM v_InventoryReportClass irc 22 | LEFT JOIN v_InventoryClassProperty icp ON icp.SMSClassID = irc.SMSClassID 23 | LEFT JOIN v_CustomInventoryReport cip ON cip.InventoryReportID = irc.InventoryReportID 24 | ORDER BY SettingName, ClassName, PropertyName" 25 | $dataset = @(Invoke-DbaQuery -SqlInstance $SQLServerName -Database "CM_$SiteCode" -Query $query -ErrorAction SilentlyContinue) 26 | $dataset | ForEach-Object { 27 | $props = [ordered]@{ 28 | SettingName = $_.SettingName 29 | ClassName = $_.ClassName 30 | PropertyName = $_.PropertyName 31 | SMSClassID = $_.SMSClassID 32 | CollectionID = $_.CollectionID 33 | } 34 | New-Object PSObject -Property $props 35 | } 36 | } 37 | catch { 38 | Write-Error "ERROR: $($Error[0].Exception.Message)" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /site/Get-CmMaintenanceTasksInfo.ps1: -------------------------------------------------------------------------------- 1 | function Get-CmMaintenanceTasksInfo { 2 | param ( 3 | [parameter(Mandatory=$False)] 4 | [string] $ServerName = "", 5 | [parameter(Mandatory=$True)] 6 | [ValidateLength(3,3)] 7 | [string] $SiteCode 8 | ) 9 | try { 10 | if (![string]::IsNullOrEmpty($ServerName)) { 11 | $Tasks = Get-WmiObject -Namespace "root/sms/site_$SiteCode" -ComputerName $ServerName -Query 'Select * from SMS_SCI_SQLTask' -ErrorAction SilentlyContinue | Sort-Object TaskName 12 | } 13 | else { 14 | $Tasks = Get-WmiObject -Namespace "root/sms/site_$SiteCode" -Query 'Select * from SMS_SCI_SQLTask' -ErrorAction SilentlyContinue | Sort-Object TaskName 15 | } 16 | $vlist = @{1 = 'Su'; 2 = 'M'; 4 = 'Tu'; 8 = 'W'; 16 = 'Th'; 32 = 'F'; 64 = 'Sa'} 17 | 18 | Foreach ($Task in $Tasks){ 19 | $tk = $Task | Select TaskName,Enabled,DeleteOlderThan,BeginTime,LatestBeginTime,DaysOfWeek 20 | $tname = $tk.TaskName 21 | $time1 = $($tk.BeginTime).Substring(8,4) 22 | $time2 = $($tk.LatestBeginTime).Substring(8,4) 23 | $t1 = $time1.Substring(0,2)+':'+$time1.Substring(2,2) 24 | $t2 = $time2.Substring(0,2)+':'+$time2.Substring(2,2) 25 | $days = ($vlist.Keys | Where-Object {$_ -band $tk.DaysOfWeek} | Sort-Object | Foreach-Object {$vlist.Item($_)}) -join ', ' 26 | $props = [ordered]@{ 27 | TaskName = $tname 28 | BeginTime = $t1 29 | EndTime = $t2 30 | DaysOfWeek = $days 31 | } 32 | New-Object PSObject -Property $props 33 | } 34 | } 35 | catch { 36 | Write-Error $Error[0].Exception.Message 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /site/Get-CmPsModulePath.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns path to the ConfigurationManager.psd1 library file 4 | .DESCRIPTION 5 | Yes, what he said 6 | .EXAMPLE 7 | Import-Module $(Get-CmPsModulePath) 8 | #> 9 | 10 | function Get-CmPsModulePath { 11 | param() 12 | $result = Get-ItemProperty "HKLM:SOFTWARE\Microsoft\SMS\Setup" | Select-Object -ExpandProperty "UI Installation Directory" 13 | $cpath = "$result\bin\ConfigurationManager.psd1" 14 | if (Test-Path $cpath) { $cpath } 15 | } 16 | -------------------------------------------------------------------------------- /site/Get-CmSiteCode.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .EXAMPLE 3 | Get-CmSiteCode -ComputerName "cm01.contoso.com" 4 | #> 5 | 6 | function Get-CmSiteCode { 7 | param ( 8 | [parameter(Mandatory=$False)] [string] $ComputerName = "" 9 | ) 10 | if ($ComputerName -ne "") { 11 | $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $ComputerName) 12 | $regKey = $Reg.OpenSubKey("SOFTWARE\Microsoft\SMS\Identification") 13 | $regKey.GetValue("Site Code") 14 | } 15 | else { 16 | $x = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\SMS\Identification" 17 | $x.'Site Code' 18 | } 19 | } -------------------------------------------------------------------------------- /site/Get-CmSiteDBInstance.ps1: -------------------------------------------------------------------------------- 1 | function Get-CmSiteDBInstance { 2 | param ( 3 | [parameter(Mandatory=$False)] [string] $ComputerName = "" 4 | ) 5 | if ($ComputerName -ne "") { 6 | $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $ComputerName) 7 | $regKey = $Reg.OpenSubKey("SOFTWARE\Microsoft\SMS\SQL Server") 8 | $regKey.GetValue("Service Name") 9 | } 10 | else { 11 | $x = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\SMS\SQL Server" 12 | $x.'Service Name' 13 | } 14 | } -------------------------------------------------------------------------------- /site/Get-CmSiteInstallPath.ps1: -------------------------------------------------------------------------------- 1 | function Get-CmSiteInstallPath { 2 | param ( 3 | [parameter(Mandatory=$False)] [string] $ComputerName = "" 4 | ) 5 | if ($ComputerName -ne "") { 6 | $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $ComputerName) 7 | $regKey = $Reg.OpenSubKey("SOFTWARE\Microsoft\SMS\setup") 8 | $regKey.GetValue("Installation Directory") 9 | } 10 | else { 11 | $x = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\SMS\setup" 12 | $x.'Installation Directory' 13 | } 14 | } -------------------------------------------------------------------------------- /site/Get-CmSiteVersion.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .EXAMPLE 3 | Get-CmSiteVersion -ComputerName "cm01.contoso.com" 4 | #> 5 | 6 | function Get-CmSiteVersion { 7 | param ( 8 | [parameter(Mandatory=$False)] [string] $ComputerName = "" 9 | ) 10 | if ($ComputerName -ne "") { 11 | $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $ComputerName) 12 | $regKey = $Reg.OpenSubKey("SOFTWARE\Microsoft\SMS\setup") 13 | $regKey.GetValue("Full Version") 14 | } 15 | else { 16 | $x = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\SMS\setup" 17 | $x.'Full Version' 18 | } 19 | } -------------------------------------------------------------------------------- /site/Get-WebServersWithSSL.ps1: -------------------------------------------------------------------------------- 1 | Import-Module WebAdministration 2 | $certCount = 0 3 | Get-ChildItem -Path IIS:SSLBindings | ForEach-Object -Process ` 4 | { 5 | if ($_.Sites) 6 | { 7 | $cert = Get-ChildItem -Path CERT:LocalMachine/My | 8 | Where-Object -Property Thumbprint -EQ -Value $_.Thumbprint 9 | 10 | if($cert) {$certCount++} 11 | 12 | } 13 | } 14 | $certCount -------------------------------------------------------------------------------- /site/Import-CMModule.ps1: -------------------------------------------------------------------------------- 1 | function Import-CmModule { 2 | if (!(Get-Module -Name "ConfigurationManager")) { 3 | if ([string]::IsNullOrEmpty($env:SMS_ADMIN_UI_PATH)) { 4 | Write-Warning "ConfigMgr Console needs to be installed on the computer where this script is used" 5 | break 6 | } 7 | $mpath = $(Get-Item $($env:SMS_ADMIN_UI_PATH)).Parent.FullName 8 | try { 9 | Import-Module $(Join-Path -Path $mpath -ChildPath "ConfigurationManager.psd1") -ErrorAction Stop 10 | Write-Verbose "configuration manager powershell module loaded successfully" 11 | } 12 | catch { 13 | Write-Error $Error[0].Exception.Message 14 | break 15 | } 16 | } 17 | (!(!(Get-Module -Name "ConfigurationManager"))) 18 | } 19 | -------------------------------------------------------------------------------- /site/Import-CmSiteBoundaries.ps1: -------------------------------------------------------------------------------- 1 | $ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition 2 | 3 | $data = Import-Csv -Path "$ScriptPath\BoundaryGroups.csv" 4 | 5 | foreach ($row in $data) { 6 | $bname = $row.Name 7 | $desc = $row.Description 8 | if ($desc -eq "") { 9 | $desc = $bname 10 | } 11 | $sitecode = $row.Site 12 | New-CmBoundaryGroup -Name $bname -Description $desc -DefaultSiteCode $sitecode 13 | } 14 | -------------------------------------------------------------------------------- /site/Send-CmSiteServerLogs.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Send-CmSiteServerLogs.ps1 collects SCCM site server logs, compresses 4 | them into a tasty little chocolate-covered ZIP file, and sends it out 5 | through the vast and spacious Internet, using Gmail as the courier 6 | pidgeon. 7 | 8 | .DESCRIPTION 9 | The Synopsis should be enough. Or maybe I'm doing this wrong? 10 | 11 | .PARAMETER SendFrom 12 | [string] (required) sender's email address 13 | 14 | .PARAMETER SendTo 15 | [string] (required) recipient's email address 16 | 17 | .PARAMETER LogFilter 18 | [string] (optional) wildcard pattern for collecting only a subset 19 | of log files to send. Example "w*" 20 | 21 | .NOTES 22 | Author..... skattebrainz.wordpress.com / GitHub / Twitter 23 | Created.... 10/27/2016 24 | Modified... 25 | Support.... 800.555.1212 26 | 27 | USE AT YOUR OWN RISK. AUTHOR IS NOT RESPONSIBLE FOR FLYING BODY PARTS. 28 | #> 29 | 30 | param ( 31 | [parameter(Mandatory=$True)] [string] $SendFrom, 32 | [parameter(Mandatory=$True)] [string] $SendTo, 33 | [parameter(Mandatory=$False)] [string] $LogFilter = "" 34 | ) 35 | 36 | $smtp = "smtp.gmail.com" 37 | $port = 587 38 | $Subject = "SCCM Log Sender`: $($env:COMPUTERNAME)" 39 | 40 | $temp = $env:TEMP 41 | 42 | if ($SendMail) { 43 | $cred = Get-Credential -Message "Provide credentials to use SMTP service" -UserName $SendFrom 44 | } 45 | 46 | <# 47 | .SYNOPSIS 48 | Get-CmSiteInstallPath returns [string] path to the base installation 49 | of System Center Configuration Manager on the site server. 50 | .DESCRIPTION 51 | Returns the full SCCM installation path using a registry query. 52 | .NOTES 53 | #> 54 | 55 | function Get-CmSiteInstallPath { 56 | $x = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\SMS\setup" 57 | $x.'Installation Directory' 58 | } 59 | 60 | # begin the assault! 61 | 62 | $cminst = Get-CmSiteInstallPath 63 | 64 | if ($cminst -ne $null) { 65 | $cmlogpath = "$cminst\logs" 66 | if (Test-Path $cmlogpath) { 67 | Write-Output "Backing up site server log files..." 68 | $src = "$temp\logtemp" 69 | if (Test-Path $src) { 70 | Write-Output "Removing previous temp folder..." 71 | rd $src -Recurse -Force 72 | } 73 | md $src 74 | if ($LogFilter -ne "") { 75 | Write-Output "Filtering logs: $LogFilter.log" 76 | copy "$cmlogpath\$LogFilter.log" "$src" 77 | $cmlogs = Get-ChildItem -Path $src -Filter "$LogFilter.log" 78 | } 79 | else { 80 | copy "$cmlogpath\*.log" "$src" 81 | $cmlogs = Get-ChildItem -Path $src -Filter "*.log" 82 | } 83 | $lc = $cmlogs.Length 84 | $dest = "$temp\sccmlogs.zip" 85 | if (Test-Path $dest) { 86 | Write-Output "Removing previous archive file..." 87 | del $dest -Force 88 | } 89 | Write-Output "Compressing backup log files..." 90 | Add-Type -AssemblyName "system.io.compression.filesystem" 91 | [io.compression.zipfile]::CreateFromDirectory($src,$dest) 92 | if (Test-Path "$dest") { 93 | $size = $(Get-Item -Path "$dest").Length 94 | $size = [math]::Round($size / 1MB,2) 95 | Write-Output "Archive created: $dest ($size MB)" 96 | if ($SendMail) { 97 | $Message = "Sending $lc SCCM Log files" 98 | Write-Output "Sending email with zip attachment..." 99 | Send-MailMessage -Subject "$Subject" -Body "$Message" -From $SendFrom -To $SendTo -SmtpServer $smtp -Attachments "$dest" -Port $Port -UseSsl -Credential $cred 100 | } 101 | Write-Output "finished!" 102 | } 103 | else { 104 | Write-Output "error: unable to create archive" 105 | } 106 | } 107 | else { 108 | Write-Output "error: unable to locate logs folder" 109 | } 110 | } 111 | else { 112 | Write-Output "error: SCCM installation path not found." 113 | } 114 | -------------------------------------------------------------------------------- /site/Set-CmLab-WsusDBFilePaths.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | Set-CmLab-WsusDBFilePaths.ps1 3 | #> 4 | [CmdletBinding()] 5 | param ( 6 | [parameter(Mandatory=$False, HelpMessage="New Database Files Path")] 7 | [string] $NewFolderPath = "G:\Database" 8 | ) 9 | $DatabaseName = "SUSDB" 10 | $ServiceName = "WsusService" 11 | $AppPool = "WsusPool" 12 | 13 | Import-Module WebAdministration 14 | Write-Verbose "stopping WSUS application pool" 15 | Stop-WebAppPool -Name $AppPool 16 | Write-Verbose "stopping WSUS service" 17 | Get-Service -Name $ServiceName | Stop-Service 18 | 19 | Import-Module SQLPS -DisableNameChecking 20 | $UpdateStatistics = $False 21 | $RemoveFullTextIndexFile = $False 22 | 23 | $ServerName = $env:COMPUTERNAME 24 | $ServerSource = New-Object "Microsoft.SqlServer.Management.Smo.Server" $ServerName 25 | 26 | Write-Verbose "detaching WSUS SUSDB database" 27 | $Db = $ServerSource.Databases | Where-Object {$_.Name -eq $DatabaseName} 28 | $CurrentPath = $Db.PrimaryFilePath 29 | $ServerSource.DetachDatabase($DatabaseName, $True, $True) 30 | $files = Get-ChildItem -Path $CurrentPath -Filter "$DatabaseName*.??f" 31 | Write-Verbose "moving database files to $NewFolderPath" 32 | $files | Move-Item -Destination $NewFolderPath 33 | $files = (Get-ChildItem -Path $NewFolderPath -Filter "$DatabaseName*.??f") | Select-Object -ExpandProperty FullName 34 | Write-Verbose "attaching database files" 35 | $ServerSource.AttachDatabase("SUSDB", $files, 'sa') 36 | 37 | Write-Verbose "starting WSUS service" 38 | Get-Service -Name $ServiceName | Start-Service 39 | 40 | Write-Verbose "starting WSUS app pool" 41 | Start-WebAppPool -Name $AppPool 42 | 43 | Write-Host "WSUS database files have been moved to $NewFolderPath" 44 | -------------------------------------------------------------------------------- /site/Set-CmLab-WsusPoolOptions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .DESCRIPTION 3 | Configure IIS app pool settings for WSUS 4 | .PARAMETER QueueLength 5 | .PARAMETER PrivateMemoryLimit 6 | .NOTES 7 | Set-CmLab-WsusPoolOptions.ps1 8 | Author: David Stein 9 | #> 10 | [CmdletBinding()] 11 | param ( 12 | [parameter(Mandatory=$False, HelpMessage="Queue Length value")] 13 | [int32] $QueueLength = 2000, 14 | [parameter(Mandatory=$False, HelpMessage="Private Memory Limit value")] 15 | [int32] $PrivateMemoryLimit = 7372800 16 | ) 17 | Import-Module WebAdministration 18 | try { 19 | Set-ItemProperty IIS:\AppPools\WsusPool -Name queueLength -Value $QueueLength 20 | Set-ItemProperty IIS:\AppPools\WsusPool -Name recycling.periodicRestart.privateMemory -Value $PrivateMemoryLimit 21 | } 22 | catch { 23 | Write-Error $_.Exception.Message 24 | } 25 | -------------------------------------------------------------------------------- /site/Set-DhcpUefiOptions.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [parameter(Mandatory=$true)] [string] $DHCPSvr, 3 | [parameter(Mandatory=$true)] [string] $DHCPFqdn, 4 | [parameter(Mandatory=$true)] [string] $PXESvr, 5 | [parameter(Mandatory=$false)] [string] $Scope_ID = "", 6 | [parameter(Mandatory=$false)] [string] $PXE64Name = "PXEClient (UEFI x64)", 7 | [parameter(Mandatory=$false)] [string] $PXE86Name = "PXEClient (UEFI x86)", 8 | [parameter(Mandatory=$false)] [string] $PXEBName = "PXEClient (BIOS x86 & x64)" 9 | ) 10 | 11 | # Write-Host "DHCP Server: $DHCPSvr, FQDN: $DHCPFqdn, PXE: $PXESvr, SCOPE: $Scope_ID" 12 | 13 | # set DHCP scope or server options for each CPU policy group 14 | 15 | function Set-DhcpV4Option { 16 | [CmdletBinding(SupportsShouldProcess)] 17 | param ( 18 | [parameter(Mandatory=$True)] [string] $ComputerName, 19 | [parameter(Mandatory=$False)] [string] $ScopeID = "" 20 | ) 21 | $x64set = @("60=PXEClient", "66=$PXESvr", "67=smsboot\x64\wdsmgfw.efi") 22 | $x86set = @("60=PXEClient", "66=$PXESvr", "67=smsboot\x86\wdsmgfw.efi") 23 | $cmbSet = @("66=$PXESvr", "67=smsboot\x64\wdsnbp.com") 24 | 25 | foreach ($bSet in $x64set) { 26 | $opt = $bSet.Split("=") 27 | if ($Scope_ID -eq "") { 28 | Write-Host "Set-DhcpServerv4OptionValue -ComputerName $ComputerName -PolicyName $PXE64Name -OptionId $($opt[0]) -Value $($opt[1])" 29 | } 30 | else { 31 | Write-Host "Set-DhcpServerv4OptionValue -ComputerName $ComputerName -PolicyName $PXE64Name -ScopeId $Scope_ID -OptionId $($opt[0]) -Value $($opt[1])" 32 | } 33 | } 34 | 35 | foreach ($bSet in $x86set) { 36 | $opt = $bSet.Split("=") 37 | if ($Scope_ID -eq "") { 38 | Write-Host "Set-DhcpServerv4OptionValue -ComputerName $ComputerName -PolicyName $PXE86Name -OptionId $($opt[0]) -Value $($opt[1])" 39 | } 40 | else { 41 | Write-Host "Set-DhcpServerv4OptionValue -ComputerName $ComputerName -PolicyName $PXE86Name -ScopeId $Scope_ID -OptionId $($opt[0]) -Value $($opt[1])" 42 | } 43 | } 44 | 45 | foreach ($bSet in $cmbSet) { 46 | $opt = $bSet.Split("=") 47 | if ($Scope_ID -eq "") { 48 | Write-Host "Set-DhcpServerv4OptionValue -ComputerName $ComputerName -PolicyName $PXEBName -OptionId $($opt[0]) -Value $($opt[1])" 49 | } 50 | else { 51 | Write-Host "Set-DhcpServerv4OptionValue -ComputerName $ComputerName -PolicyName $PXEBName -ScopeId $Scope_ID -OptionId $($opt[0]) -Value $($opt[1])" 52 | } 53 | } 54 | } 55 | 56 | function Set-DhcpV4Policy { 57 | param ( 58 | [parameter(Mandatory=$True)] [string] $DHCPFQDN 59 | ) 60 | foreach ($polSet in @("$PXE64Name","$PXE86Name","$PXEBName")) { 61 | Write-Host "Set-DhcpServerv4Policy -Name $polSet -Description "Set correct server and file name for $polSet" -Condition OR -VendorClass EQ -ComputerName $DHCPFQDN" 62 | } 63 | } 64 | 65 | function Set-DhcpV4Class { 66 | param ( 67 | [parameter(Mandatory=$True)] [string] $DHCPHostName 68 | ) 69 | foreach ($clSet in @("$PXE64Name=PXE:Arch:00007", "$PXE86Name=PXE:Arch:00006", "$PXEBName=PXE:Arch:00000")) { 70 | $Dclass = $clSet.Split("=") 71 | Write-Host "Add-DhcpServerv4Class -Name "$($Dclass[0])" -Description "$($Dclass[1])" -Type Vendor -Data "$($Dclass[1])" -Computer $DHCPHostName" 72 | } 73 | } 74 | 75 | #-------------------------------------------------------------------------------------------------------------------- 76 | 77 | # Set Vendor Classes: 78 | 79 | Set-DhcpV4Class -DHCPHostName $DHCPSvr 80 | 81 | # Create DHCP Policies (Leaving out the “ScopeId” option will make the policy a server level policy): 82 | 83 | Set-DhcpV4Policy -DHCPFQDN $DhcpFqdn 84 | 85 | Set-DhcpV4Option -ComputerName $DHCPSvr -ScopeID 192.168.29.0 86 | -------------------------------------------------------------------------------- /site/Set-MdtSharePermissions.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Configure security and share permissions for MDT deployment share 4 | .PARAMETER DeploymentShareNTFS 5 | [string] (required) NTFS file path for deployment share 6 | .PARAMETER DeploymentShareName 7 | [string] (required) Name of deployment name share 8 | .PARAMETER CaptureAccount 9 | [string] (required) name of MDT build/capture account 10 | .NOTES 11 | adapted slightly from https://deploymentresearch.com/Research/Post/518/Fixing-MDT-2013-Update-1-deployment-share-permissions-using-PowerShell 12 | #> 13 | 14 | param ( 15 | [parameter(Mandatory=$True)] 16 | [ValidateNotNullOrEmpty()] 17 | [string] $DeploymentShareNTFS, 18 | [parameter(Mandatory=$True)] 19 | [ValidateNotNullOrEmpty()] 20 | [string] $DeploymentShareName, 21 | [parameter(Mandatory=$True)] 22 | [ValidateNotNullOrEmpty()] 23 | [string] $CaptureAccount 24 | ) 25 | 26 | if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) 27 | { 28 | Write-Warning "Oops, you need to run this script from an elevated PowerShell prompt!`nPlease start the PowerShell prompt as an Administrator and re-run the script." 29 | Write-Warning "Aborting script..." 30 | Break 31 | } 32 | 33 | # Configure NTFS Permissions for the MDT Build Lab deployment share 34 | icacls $DeploymentShareNTFS /grant '"Users":(OI)(CI)(RX)' 35 | icacls $DeploymentShareNTFS /grant '"Administrators":(OI)(CI)(F)' 36 | icacls $DeploymentShareNTFS /grant '"SYSTEM":(OI)(CI)(F)' 37 | icacls "$DeploymentShareNTFS\Captures" /grant ""$CaptureAccount":(OI)(CI)(M)" 38 | 39 | # Configure Sharing Permissions for the MDT Build Lab deployment share 40 | # Note: Original uses "Change" rather than "Full" 41 | Grant-SmbShareAccess -Name $DeploymentShareName -AccountName "EVERYONE" -AccessRight Full -Force 42 | Revoke-SmbShareAccess -Name $DeploymentShareName -AccountName "CREATOR OWNER" -Force 43 | -------------------------------------------------------------------------------- /site/Test-CmPorts.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [parameter(Mandatory=$True)] 3 | [ValidateNotNullOrEmpty()] 4 | [string] $IPAddress 5 | ) 6 | $ports = @(80,443,1433,10123) 7 | if (Test-Connection -ComputerName $IPAddress -Count 1 -TimeToLive 1 -Quiet) { 8 | Write-Host "Host is online" -ForegroundColor Green 9 | foreach ($port in $ports) { 10 | try { 11 | $test = New-Object System.Net.Sockets.TcpClient("$IPAddress", "$port") -ErrorAction Stop 12 | Write-Host "Port is open: $port" -ForegroundColor Green 13 | } 14 | catch { 15 | Write-Host "Port not accessible: $port" -ForegroundColor DarkRed 16 | } 17 | } 18 | } 19 | else { 20 | Write-Host "Host is not online: $IPAddress" -ForegroundColor DarkMagenta 21 | } 22 | -------------------------------------------------------------------------------- /site/Update-CmAppSourcePaths.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Replace Deployment Type source folder assignments using explicit mapping 4 | 5 | .DESCRIPTION 6 | I hope the synopsis is enough, otherwise I've failed miserably. 7 | 8 | .NOTES 9 | Lazy hack: David Stein 10 | 11 | .LINK 12 | http://skatterbrainz.wordpress.com 13 | 14 | .EXAMPLE 15 | .\Update-CmAppSourcePaths.ps1 16 | 17 | #> 18 | 19 | function Get-CmAdminConsolePath { 20 | $result = Get-ItemProperty "HKLM:SOFTWARE\Microsoft\SMS\Setup" | 21 | Select-Object -ExpandProperty "UI Installation Directory" 22 | $cpath = "$result\bin\ConfigurationManager.psd1" 23 | if (Test-Path $cpath) { $cpath } 24 | } 25 | 26 | function Swap-Paths { 27 | param ( 28 | [parameter(Mandatory=$False)] 29 | [string] $SourcePath = "" 30 | ) 31 | $newPath = "" 32 | if ($SourcePath -ne "") { 33 | $newPath = $SourcePath.ToLower().replace("\\server1.contoso.com\apps$", "\\FS1.fabrikam.com\DSL$\Apps") 34 | $newPath = $newPath.ToLower().replace("\\Apps1.fubar.com\software$\apps", "\\FS2.fabrikam.com\DSL$\Apps") 35 | } 36 | return $newPath 37 | } 38 | 39 | Import-Module $(Get-CmAdminConsolePath) 40 | 41 | $SiteCode = Get-ItemProperty "HKLM:SOFTWARE\Microsoft\SMS\Identification" -Name "Site Code" | Select-Object -ExpandProperty "Site Code" 42 | cd "$SiteCode`:" 43 | 44 | Write-Host "Querying Applications..." -ForegroundColor Cyan 45 | 46 | $Apps = Get-CMApplication 47 | $AppNames = $Apps.LocalizedDisplayName 48 | $AppCount = $AppNames.Count 49 | $RowCount = 1 50 | 51 | Write-Host "Returned $AppCount objects" 52 | 53 | foreach ($AppName in $AppNames) { 54 | Write-Host "Application: $AppName ($RowCount of $AppCount)" -ForegroundColor White 55 | $DtNames = Get-CMDeploymentType -ApplicationName $AppName 56 | Write-Host "Querying Deployment types..." -ForegroundColor Cyan 57 | foreach ($dt in $DtNames) { 58 | $DtSDMPackageXML = $dt.SDMPackageXML 59 | $DtSDMPackageXML = [xml]$DtSDMPackageXML 60 | $DtLocalName = $dt.LocalizedDisplayName 61 | $DtCleanPath = "" 62 | $DtCleanPath = $DtSDMPackageXML.AppMgmtDigest.DeploymentType.Installer.Contents.Content.Location[0] 63 | 64 | # check if array returned only a "\" value, indicating a singular value 65 | if ($DtPath.Length -lt 2) { 66 | $DtPath = $DtSDMPackageXML.AppMgmtDigest.DeploymentType.Installer.Contents.Content.Location 67 | } 68 | Write-Host "Current source: $DtPath" -ForegroundColor Cyan 69 | $NewDtPath = Swap-Paths -SourcePath $DtPath 70 | Write-Host "New directory source: $NewDtPath" -ForegroundColor Green 71 | if ($NewDtPath -ne "") { 72 | if ($NewDtPath.ToLower() -ne $DtPath.ToLower()) { 73 | Set-CMDeploymentType -ApplicationName "$AppName" -DeploymentTypeName $DtLocalName -MsiOrScriptInstaller -ContentLocation "$NewDtPath" 74 | Write-Host "Updating: $DtLocalName" -ForegroundColor Cyan 75 | } 76 | else { 77 | Write-Host "No changes made" -ForegroundColor Cyan 78 | } 79 | } 80 | } 81 | Write-Host "--------------" 82 | $RowCount++ 83 | } -------------------------------------------------------------------------------- /site/Update-CmPackageSourcePaths.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Replace PkgSourcePath assignments using explicit mapping 4 | 5 | .DESCRIPTION 6 | I hope the synopsis is enough, otherwise I've failed miserably. 7 | 8 | .NOTES 9 | Lazy hack: David Stein 10 | 11 | .LINK 12 | http://skatterbrainz.wordpress.com 13 | 14 | .EXAMPLE 15 | .\Update-CmPackageSourcePaths.ps1 16 | 17 | #> 18 | 19 | function Get-CmAdminConsolePath { 20 | $result = Get-ItemProperty "HKLM:SOFTWARE\Microsoft\SMS\Setup" | 21 | Select-Object -ExpandProperty "UI Installation Directory" 22 | $cpath = "$result\bin\ConfigurationManager.psd1" 23 | if (Test-Path $cpath) { $cpath } 24 | } 25 | 26 | function Swap-Paths { 27 | param ( 28 | [parameter(Mandatory=$False)] 29 | [string] $SourcePath = "" 30 | ) 31 | $newPath = "" 32 | if ($SourcePath -ne "") { 33 | $newPath = $SourcePath.ToLower().replace("\\server1.contoso.com\apps$", "\\FS1.fabrikam.com\DSL$\Apps") 34 | $newPath = $newPath.ToLower().replace("\\Apps1.fubar.com\software$\apps", "\\FS2.fabrikam.com\DSL$\Apps") 35 | } 36 | return $newPath 37 | } 38 | 39 | Import-Module $(Get-CmAdminConsolePath) 40 | 41 | $SiteCode = Get-ItemProperty "HKLM:SOFTWARE\Microsoft\SMS\Identification" -Name "Site Code" | Select-Object -ExpandProperty "Site Code" 42 | cd "$SiteCode`:" 43 | 44 | $pkgs = Get-CMPackage 45 | 46 | foreach ($pkg in $pkgs) { 47 | Write-Host "PackageID: $($pkg.PackageID)" 48 | Write-Host "Name: $($pkg.Name)" 49 | $z = $pkg.PkgSourcePath 50 | Write-Host "Old Source: $z" 51 | $x = Swap-Paths -SourcePath $pkg.PkgSourcePath 52 | Write-Host "New Source: $x" 53 | if ($x -ne "") { 54 | if ($x.ToLower() -ne $z.ToLower()) { 55 | Write-Host "updating pacakge source path..." 56 | Set-CMPackage -Id $pkg.PackageID -Path $x 57 | } 58 | } 59 | write-host "----" 60 | } 61 | 62 | Write-Host "all done. go drink!" -------------------------------------------------------------------------------- /site/sqlversions.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skatterbrainz/sccm/011611aeaa75e67817c6bd671906bb1f0c79a6e5/site/sqlversions.csv -------------------------------------------------------------------------------- /site/sqlversions.csv.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skatterbrainz/sccm/011611aeaa75e67817c6bd671906bb1f0c79a6e5/site/sqlversions.csv.xlsx --------------------------------------------------------------------------------