This article addresses some common questions about WSUS maintenance for Configuration Manager environments.
Tag Archives: Script
Get AD Nested Group Members with Powershell
Use the following script to get nested AD group members using powershell.
Import-Module ActiveDirectory
function Get-ADNestedGroupMembers {
[cmdletbinding()]
param ( [String] $Group )
Import-Module ActiveDirectory
$Members = Get-ADGroupMember -Identity $Group -Recursive | select samaccountname | %{Get-ADUser $_.samaccountname -Properties mail}
$members
}
Get-ADNestedGroupMembers "GROUP" | Select Name,SamAccountName,mail,enabled
Office 365 Hide mailboxes from the GAL
Export all mailboxes who are shown in the GAL
Get-Mailbox -ResultSize Unlimited | Where {$_.HiddenFromAddressListsEnabled -eq $false}| select UserPrincipalname, HiddenFromAddressListsEnabled | Export-Csv "c:\temp\gal.csv" -NoTypeInformation -Encoding UTF8
Show all private groups which are shown in the GAL (Teams groups are default hidden)
Get-UnifiedGroup | Where-Object {$_.AccessType -eq 'Private'} | select Displayname, PrimarySMTPAddress
To hide a single mailbox use the following command:
Set-Mailbox -Identity [email protected] -HiddenFromAddressListsEnabled $true
To hide multiple mailboxes from the GAL, create a CSV file and use that as input to hide the mailboxes:
Import-Csv 'C:\Hide_Mailboxes.csv' | ForEach-Object {
$upn = $_."UserPrincipalName"
Set-Mailbox -Identity $upn -HiddenFromAddressListsEnabled $true
}
To hide a single group use the following command:
Set-UnifiedGroup <group> -HiddenFromAddressListsEnabled $true
Or hide all private groups at once:
Get-UnifiedGroup | Where-Object {$_.AccessType -eq 'Private'} | Set-UnifiedGroup -HiddenFromAddressListsEnabled $true
Sources:
Find mailboxes hidden from the GAL using Powershell – MorganTechSpace
Hide Office 365 Group from GAL using Powershell – MorganTechSpace
Check Microsoft 365 email forward
When you want to know which users has email forwards on their Microsoft 365 mailbox, use the following powershell command:
Get-Mailbox -Filter {ForwardingsmtpAddress -ne $null} | ft Name,ForwardingsmtpAddress,DeliverToMailboxAndForward -Autosize
This will list all mailboxes with an forwarding rule.
Windows Backup Mail Report Script
Earlier i wrote a script to check for windows server backup results. At the next site a better script is written to report the results of windows server backup:
https://jocha.se/blog/tech/wbadmin-backup-mail-report
The following script is from this site:
<# .SYNOPSIS Windows Backup Mail Report Written by Joakim, http://jocha.se .DESCRIPTION Version 4.1 - Updated 2016-05-31 This script will mail a report from the latest Windows Backup job, can also fetch and generate reports from remote servers. The script requires at least PowerShell v3. .EXAMPLE To automate this script, setup a scheduled task. Name: Backup Email Task Description: Notifies backup admin of scheduled backup status Run whether user is logged on or not Trigger > On event > Log=Microsoft-Windows-Backup/Operational > Source=Backup > Event ID(s)= 4,5,8,9,17,22,49,50,52,100,517,518,521,527,528,544,545,546,561,564,612 Action: Start a Program Program: Powershell Arguments: -Command "C:\Scripts\WBJobReport.ps1" -ExecutionPolicy Bypass #> Add-PSSnapin Windows.ServerBackup -ErrorAction SilentlyContinue ####################################### #-------- Variables to change --------# # Uncomment the two rows below and row 207 to enable "Remote Report" generation. #$Servers = New-PSSession -Computername Server01, Server02, Server03 #Invoke-Command -Session $Servers { # Set your Company name $Company = "MyCompany" # Set the recipient/sender email-address $MailTo = "[email protected]" $MailFrom = "$Company Backup <[email protected]>" # SMTP user account password $MailUser = "MyUser" $MailPassword = "MyPassword" # SMTP Server $MailServer = "smtpserver.company.com" # SMTP Port $MailPort = 587 # If your server uses SSL, otherwise set to $false $UseSSL = $true #---- Don't change anything below ----# ####################################### Try { $CurrentTime = (Get-Date).ToString("yyyy-MM-dd HH:mm") $Computer = Get-Content env:computername $WBJob = Get-WBJob -Previous 1 $WBSummary = Get-WBSummary $WBLastSuccess = ($WBSummary.LastSuccessfulBackupTime).ToString("yyyy-MM-dd HH:mm") $WBResult = $WBSummary.LastBackupResultHR $WBErrorMsg = $WBJob.ErrorDescription + "`n" + $WBSummary.DetailedMessage $WBStartTime = $WBJob.StartTime $WBEndTime = $WBJob.EndTime $WBDuration = (New-TimeSpan -Start $WBStartTime -End $WBEndTime) $Password = ConvertTo-SecureString $MailPassword -AsPlainText -Force $Credentials = New-Object System.Management.Automation.PSCredential ($MailUser, $Password) Function FormatBytes { Param ( [System.Int64]$Bytes ) [string]$BigBytes = "" #Convert to TB If ($Bytes -ge 1TB) {$BigBytes = [math]::round($Bytes / 1TB, 2); $BigBytes += " TB"} #Convert to GB ElseIf ($Bytes -ge 1GB) {$BigBytes = [math]::round($Bytes / 1GB, 2); $BigBytes += " GB"} #Convert to MB ElseIf ($Bytes -ge 1MB) {$BigBytes = [math]::round($Bytes / 1MB, 2); $BigBytes += " MB"} #Convert to KB ElseIf ($Bytes -ge 1KB) {$BigBytes = [math]::round($Bytes / 1KB, 2); $BigBytes += " KB"} #If smaller than 1KB, leave at bytes. Else {$BigBytes = $Bytes; $BigBytes += " Bytes"} Return $BigBytes } Function Log-BackupItems { Param ( [System.String]$Name, [System.String]$Status, [System.Int64]$Bytes ) $Item = New-Object System.Object; $Item | Add-Member -Type NoteProperty -Name "Name" -Value $Name; $Item | Add-Member -Type NoteProperty -Name "Status" -Value $Status; $Item | Add-Member -Type NoteProperty -Name "Size" -Value (FormatBytes -Bytes $Bytes); Return $Item; } $results=@() $WBJob | % { $_.JobItems | % { $BackupItem = $null If ($_.Name -eq 'VolumeList') { $_ | % {$_.SubItemList | % { $BackupItem = Log-BackupItems -Name $_.Name -Status $_.State -Bytes $_.TotalBytes $results += $BackupItem }} } Else { $_ | % { $BackupItem = Log-BackupItems -Name $_.Name -Status $_.State -Bytes $_.TotalBytes $results += $BackupItem } } } } # Change Result of 0 to Success in green text and any other result as Failure in red text If ($WBResult -eq 0) { $WBResult = "Successful"} Else {$WBResult = "Failed"} # Assemble the HTML Report $HTMLMessage = @" <!DOCTYPE html> <html> <head> <title>$Company Backup Report for $Computer</title> <style> body { font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 12px } h3{ clear: both; font-size: 150%; margin-left: 20px;margin-top: 30px; } table { padding: 15px 0 20px; width: 500px; text-align: left; } td, th { padding: 0 20px 0 0; margin 0; text-align: left; } th { margin-top: 15px } a, a:visited { color: #2ea3f2; text-decoration: none; } #Report { width: 600px; } #Successful { color: green } #Failed { color: red } </style> </head> <body> <div id="Report"> <p><h3><a href="http://jocha.se">$Company Backup Report for $Computer</a></p></h3> <table id="summary"><tbody> <tr><td>Todays date:</td> <td>$CurrentTime</td></tr> <tr><td>Last Successful Backup:</td> <td>$WBLastSuccess</td></tr> <tr><td>Start time last backup:</td> <td>$WBStartTime</td></tr> <tr><td>End time last backup:</td> <td>$WBEndTime</td></tr> <tr><td>Duration last backup:</td> <td>$WBDuration</td></tr> <tr><td>Backup Result:</td> <td><b id="$WBResult">$WBResult</b></td></tr> <tr><td>Error Message (if applicable):</td> <td>$WBErrorMsg</td></tr></tbody></table> $( $html = $results | ConvertTo-HTML -Fragment $xml=[xml]$html $attr=$xml.CreateAttribute('id') $attr.Value='items' $xml.table.Attributes.Append($attr) | out-null $html=$xml.OuterXml | out-string $html ) </div> </body> </html> "@ $email = @{ SMTPServer = $MailServer UseSSL = $UseSSL BodyAsHtml = $true Port = $MailPort Credential = $Credentials Encoding = ([System.Text.Encoding]::UTF8) To = $MailTo From = $MailFrom Subject = "$WBResult Backup on $Computer" Body = $HTMLMessage } Send-MailMessage @email } Catch { $email = @{ SMTPServer = $MailServer BodyAsHtml = $true UseSSL = $UseSSL # Port is a PowerShell v3 variable Port = $MailPort Credential = $Credentials Encoding = ([System.Text.Encoding]::UTF8) To = $MailTo From = $MailFrom Subject = "Failed Backup on $Computer" Body = "The backup script failed to run!" } Send-MailMessage @email } # Uncomment below to enable "Remote Report". #}
To backup a domain controller with powershell. Use the script below to place it on the network. This scripts requires the Windows Server Backup Feature and can be scheduled
Import-Module ServerManager
[string]$date = get-date -f 'yyyy-MM-dd'
$path=”\\server\directory”
$TargetUNC=$path+'-'+$date
$TestTargetUNC= Test-Path -Path $TargetUNC
if (!($TestTargetUNC)){
New-Item -Path $TargetUNC -ItemType directory
}
$WBadmin_cmd = "wbadmin.exe START BACKUP -backupTarget:$TargetUNC -systemState -noverify -vssCopy -quiet"
Invoke-Expression $WBadmin_cmd
If an error occurs:
Detailed error: The filename, directory name, or volume label syntax is incorrect. The backup of the system state failed
Make sure all drivers are set correct. In my case changing the path of vsock did the trick. How to find the driver path? Open an elevated prompt and execute the following commands:
DiskShadow /L writers.txt list writers detailed
Check the directories, in my case the string which was found was the following:
File List: Path = c:\windows\\systemroot\system32\drivers, Filespec = vsock.sys
To correct the path, open the Registry Editor and go to reg key HKLM\SYSTEM\CurrentControlSet\Services\vsock
Change the ImagePath value from
\systemroot\system32\DRIVERS\vsock.sys
toSystem32\DRIVERS\vsock.sys
Run the backup again, it should say:
The backup operation successfully completed. The backup of volume (C:) completed successfully. The backup of the system state successfully completed [01.06.2020 09:52].
source: http://woshub.com/backup-active-directory-domain-controller/
ACL script to determine folder permissions
To determine the ACL’s on a specific foldertree use the following script. It will display the Path, FileSystemRights, IsInherited, Name of the underlying folders.
$path = "\\server\path\"
$targetFile = "file.csv" # Not working yet
$foldersToQuery = Get-ChildItem $Path | Where {$_.PSIsContainer} | select -expandproperty FullName
# Get access list, change any domain
foreach ($folder in $foldersToQuery) {
$Access = (Get-Acl $Folder).Access |
Select-Object @{n='Path';e={ $Folder }}, *,
@{n='ADObject';e={
If ($_.IdentityReference -NotMatch "^(NT AUTH|BUILTIN|$($Env:ComputerName))") {
$Searcher = [ADSISearcher]"(sAMAccountName=$($_.IdentityReference -Replace '^.+\\'))"
$Searcher.PropertiesToLoad.AddRange(@("name", "distinguishedName", "objectClass"))
$Searcher.FindOne()
} }} |
Select-Object *, @{n='Name';e={ $_.ADObject.Properties['name'][0] }},
@{n='DN';e={ $_.ADObject.Properties['distinguishedname'][0] }},
@{n='Class';e={ ([String[]]$_.ADObject.Properties['objectclass'])[-1] }} -Exclude ADObject
$Access | ForEach-Object {
$Entry = $_
If ($Entry.Class -eq 'group') {
$Searcher = [ADSISearcher]"(memberOf:1.2.840.113556.1.4.1941:=$($Entry.DN))"
$Searcher.PageSize = 1000
$Searcher.PropertiesToLoad.AddRange(@("name", "distinguishedName", "objectClass"))
$Searcher.FindAll() | ForEach-Object {
$ADObject = $_
$Entry | Select-Object *, @{n='Name';e={ $ADObject.Properties['name'][0] }},
@{n='DN';e={ $ADObject.Properties['distinguishedname'][0] }},
@{n='Class';e={ ([String[]]$ADObject.Properties['objectclass'])[-1] }} -Exclude Name, DN, Class
}
} Else {
$Entry
}
} | ft Path, FileSystemRights, IsInherited, Name, class -AutoSize
}
Backup all SQL databases
The following script can be used to backup all databases from a SQL server. The system databases are excluded. If any other database should be excluded, add them to the “NOT IN” section.
For different date formats in the export, check: https://robbamforth.wordpress.com/2010/06/11/sql-date-formats-getdate-examples/
The script is exporting the databases now with the following format: databasename_YYMMDD.bak
DECLARE @name VARCHAR(50) -- database name
DECLARE @path VARCHAR(256) -- path for backup files
DECLARE @fileName VARCHAR(256) -- filename for backup
DECLARE @fileDate VARCHAR(20) -- used for file name
-- specify database backup directory
SET @path = 'C:\Backup\'
-- specify filename format
SELECT @fileDate = CONVERT(VARCHAR(8),GETDATE(),112)
DECLARE db_cursor CURSOR READ_ONLY FOR
SELECT name
FROM master.sys.databases
WHERE name NOT IN ('master','model','msdb','tempdb') -- exclude these databases
AND state = 0 -- database is online
AND is_in_standby = 0 -- database is not read only for log shipping
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @fileName = @path + @name + '_' + @fileDate + '.BAK'
BACKUP DATABASE @name TO DISK = @fileName
FETCH NEXT FROM db_cursor INTO @name
END
CLOSE db_cursor
DEALLOCATE db_cursor
Reset 120 Day Grace Period for Windows RDS Server with PowerShell
Use the following Powershell script to reset the Grace Period of a Windows RDS Server
Because the original script has been removed from the script center ( https://gallery.technet.microsoft.com/scriptcenter/Reset-Terminal-Server-RDS-44922d91), a copy can be found below:
## This Script is intended to be used for Querying remaining time and resetting Terminal Server (RDS) Grace Licensing Period to Default 120 Days.
## Developed by Prakash Kumar ([email protected]) May 28th 2016
## www.adminthing.blogspot.com
## Disclaimer: Please test this script in your test environment before executing on any production server.
## Author will not be responsible for any misuse/damage caused by using it.
Clear-Host
$ErrorActionPreference = "SilentlyContinue"
## Display current Status of remaining days from Grace period.
$GracePeriod = (Invoke-WmiMethod -PATH (gwmi -namespace root\cimv2\terminalservices -class win32_terminalservicesetting).__PATH -name GetGracePeriodDays).daysleft
Write-Host -fore Green ======================================================
Write-Host -fore Green 'Terminal Server (RDS) grace period Days remaining are' : $GracePeriod
Write-Host -fore Green ======================================================
Write-Host
$Response = Read-Host "Do you want to reset Terminal Server (RDS) Grace period to Default 120 Days ? (Y/N)"
if ($Response -eq "Y") {
## Reset Terminal Services Grace period to 120 Days
$definition = @"
using System;
using System.Runtime.InteropServices;
namespace Win32Api
{
public class NtDll
{
[DllImport("ntdll.dll", EntryPoint="RtlAdjustPrivilege")]
public static extern int RtlAdjustPrivilege(ulong Privilege, bool Enable, bool CurrentThread, ref bool Enabled);
}
}
"@
Add-Type -TypeDefinition $definition -PassThru
$bEnabled = $false
## Enable SeTakeOwnershipPrivilege
$res = [Win32Api.NtDll]::RtlAdjustPrivilege(9, $true, $false, [ref]$bEnabled)
## Take Ownership on the Key
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Control\Terminal Server\RCM\GracePeriod", [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::takeownership)
$acl = $key.GetAccessControl()
$acl.SetOwner([System.Security.Principal.NTAccount]"Administrators")
$key.SetAccessControl($acl)
## Assign Full Controll permissions to Administrators on the key.
$rule = New-Object System.Security.AccessControl.RegistryAccessRule ("Administrators","FullControl","Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)
## Finally Delete the key which resets the Grace Period counter to 120 Days.
Remove-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\RCM\GracePeriod'
write-host
Write-host -ForegroundColor Red 'Resetting, Please Wait....'
Start-Sleep -Seconds 10
}
Else
{
Write-Host
Write-Host -ForegroundColor Yellow '**You Chose not to reset Grace period of Terminal Server (RDS) Licensing'
}
## Display Remaining Days again as final status
tlsbln.exe
$GracePost = (Invoke-WmiMethod -PATH (gwmi -namespace root\cimv2\terminalservices -class win32_terminalservicesetting).__PATH -name GetGracePeriodDays).daysleft
Write-Host
Write-Host -fore Yellow =====================================================
Write-Host -fore Yellow 'Terminal Server (RDS) grace period Days remaining are' : $GracePost
Write-Host -fore Yellow =====================================================
## Cleanup of Variables
Remove-Variable * -ErrorAction SilentlyContinue
NetApp & Powershell – Snapshot Report
source: https://nmanzi.com/netapp-powershell-snapshot-report/
Nathan Manzi has created a powershell script for reporting snapshots on a Netapp. The script below has been altered for a cluster mode instead of a 7 mode. Also, a few parameters have been set to optional with default settings. This way, these settings does not needs to be entered when running the script.
Also when reporting on multiple netapp’s, all volumes with no snapshots comes on top of the mail. Below there, all old snapshots (older then $WarningDays) are displayed.
In $ExcludedVolumes alle volumes can be written down for which no results needed to be displayed
The script can be run with the following command:
.\NetApp-SnapshotReport.ps1 -Username <user> -Password <"pass">
The report will be delivered in the mail:

Download the file below: