Remote Powershell

Clean print servers of old jobs

Been working on some maintenance, cleanup, auditing, streamlining for a customer. During this workthrough, printjobs showed up and asking around they actually performed this task manually. Of course I would not hear of this and created a simple powershell script that would go through all print servers, look for jobs older than 7 days and delete them. All wrapped in standard remote powershell, so this can be run from a central batch server.
1: Make sure to add your printservers to the array.
2: This script requires remote powershell to work 🙂
3: You can change the number of days to reflect your own requirements.

$PrintServers = @("<PrintSRV01>","<PrintSRV02>", "<PrintSRV03>", "<PrintSRV04>")

Foreach($Printserver in $PrintServers) 
$Session = New-PSSession -Computername $PrintServer -Authentication Kerberos
$SC = { 
$OldJobs = get-wmiobject -class "Win32_PrintJob" -namespace "root\CIMV2" | Where-Object { $_.StartTime -lt $($(Get-Date).addDays(-7)) }
foreach ($job in $OldJobs) 

Invoke-Command -Session $Session -ScriptBlock $SC
Remove-PSSession $Session

Invoke-Command – Remote Powershell – Variables

Often have some issues figuring out just exactly how to do remote pssessions, passing variables, performing different stuff. I found, what I believe is the best solution for script based remote powershell for more complex operations. The below example is remote session against an SQL server, using loading some pssnapins using sqlcmd to set some database options. I use this example, because I find it a good demonstration on how and what is possible. The first example connections to basic server. The second example to an Exchange server, as the powershell connection string is different.

#– Basic server remote powershell with variables

$Session = New-PSSession -Computername $SQLServer -Authentication Kerberos
$SQLOptions = {param([Parameter(Mandatory=$true)]$Database,[Parameter(Mandatory=$true)]$DatabaseLog,[Parameter(Mandatory=$true)]$Instance)
	Add-PSSnapin sqlserverprovidersnapin100
	Add-PSSnapin sqlservercmdletsnapin100
	Invoke-SQLcmd -Query "USE master;ALTER DATABASE $Database SET RECOVERY FULL, AUTO_UPDATE_STATISTICS ON;" -ServerInstance "$Instance"
	Invoke-SQLcmd -Query "USE master;ALTER DATABASE $Database MODIFY FILE (NAME= $Database,FILEGROWTH= 150MB, MAXSIZE= UNLIMITED);" -ServerInstance "$Instance"
	Invoke-SQLcmd -Query "USE master;ALTER DATABASE $Database MODIFY FILE (NAME= $DatabaseLog,FILEGROWTH= 150MB, MAXSIZE= UNLIMITED);" -ServerInstance "$Instance"

	Invoke-Command -ArgumentList $Database, $DatabaseLog, $Instance -Session $Session -ScriptBlock $SQLOptions
	Remove-PSSession $Session

#– Exchange remote powershell with variables. Difference in Session string.

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://"$MailServer"/PowerShell/ -Authentication Kerberos
$SendSettings = {param([Parameter(Mandatory=$true)]$MailServer,[Parameter(Mandatory=$true)]$Domain
	new-SendConnector -Name "$Domain" -Usage "Custom" -AddressSpaces "SMTP:$Domain;1" -IsScopedConnector $false -DNSRoutingEnabled $true -UseExternalDNSServersEnabled $false -SourceTransportServers '$MailServer'
	new-AcceptedDomain -Name "$Domain" -DomainName "$Domain" -DomainType 'ExternalRelay'
Invoke-Command $Session -Argumentlist $Mailserver, $Domain -Scriptblock $SendSettings | Out-Null
Remove-PSSession $Session

Get, Set Time with Powershell

Had some challenges with time on some virtual environments that got reverted to snapshot each day and redeployed. Domain Controller was not connected to the Internet and host time synchronization caused some issues here. Basically we created a script which polled a public NTP pool and changed DC time accordingly, using remote powershell from server connected to DC and the Internet.

#--Find the FQDN of the DC.
$DC=([]::GetHostByAddress(([System.Net.Dns]::GetHostAddresses($(gwmi WIN32_ComputerSystem).Domain)[0].IPAddressToString))).hostname
#-- Creates Session to the DC.
$Session= New-PSSession -computername $DC -authentication Kerberos

#-- Collects time from dk ntp pool.
$Time = w32tm /stripchart /dataonly / /samples:1
#-- Gets local time of server
$LocalTime = Get-Date

#-- Synchronizes Local time with NTP pool time, using difference in time.
$SetTime= ($LocalTime.AddSeconds($Time[3].split("")[1].trim("+s")))

#-- Creates scriptblock to be run on DC
$SB= {param($SetTime)Set-Date $SetTime}

#-- Sets time according to on Domain Controller
Invoke-Command $Session -ArgumentList $SetTime -Scriptblock $SB

#-- Removes Session to DC
Remove-PSSession $Session

Get a Domain Controller from any domain member

I needed to find an available domain controller in order to remote Powershell and use some AD modules. Didn’t want to start installing them on random machines. So how to find a DC? If you RDP, you can just write the domain name and it finds the first available DC. However that didn’t work for my PSSession, so what to do.

Turns out there was a neet oneliner for that 🙂

[System.Net.Dns]::GetHostAddresses($(gwmi WIN32_ComputerSystem).Domain)[0].IPAddressToString

Returns the IP Adress of the first available DC, which works, but not so good. As it’s impossible to use Kerberos when using IP, well this can be turned into host name also in a one liner:

([]::GetHostByAddress(([System.Net.Dns]::GetHostAddresses($(gwmi WIN32_ComputerSystem).Domain)[0].IPAddressToString))).hostname

Gotta love great colleagues !