So here's the scope of what I'm trying to do:
Get remote computer information for Windows computers in multiple sites and write the information found to the .Description property of each computer object in Active Directory. If the script can't connect to the remote machine, log that information into a text file and don't make any changes to the computer object that can't be connected to.
In order to time how long the script is taking to run, I have a second script that measures the execution time.
I have this setup as a scheduled task to run the second script (which calls the first) that is executed via a batch file on a Windows 7 Pro virtual machine.
My problem is I believe the script may be running into memory problems based on the information I see in my log. Any help on possible diagnosing the root cause would be appreciated to the extreme. Without further adieu, here's my code for both scripts as well as a sample of the strange log output.
Main Script (script 1):
set-location \\myscriptcomputer\c$\somefolder\PSScripts
enter code here`function Measure-Latest {
BEGIN { $latestlogon = $null }
PROCESS {
if (($_ -ne $null) -and (($latestlogon -eq $null) -or ($_ -gt $latestlogon))) {
$latestlogon = $_
}
}
END { $latestlogon }
}
Function CreateLog {
#Create a log file
$global:path = "C:\Somefolder\PSScripts\WriteComputerDescriptions"
$global:LogTime = Get-Date -Format "MM-dd-yyyy_hh-mm-ss"
$global:LogName = 'CompDescriptions'
$global:LogFile = 'C:\Somefolder\PSScripts\WriteComputerDescriptions\'+$LogName+$LogTime+'.txt'
Write-Host "Creating log file" -foregroundcolor yellow
if([IO.Directory]::Exists($global:path))
{
#Do Nothing
}
else
{
New-Item -ItemType directory -Path C:\Somefolder\PSScripts\WriteComputerDescriptions
}
cd C:\Somefolder\PSScripts\WriteComputerDescriptions
echo "WriteComputerDescriptions Script Log" >> $global:logfile
}
Function WriteDescription {
Write-Host "Gathering Computer information..." -foregroundcolor yellow
$UserWorkstations = get-qadcomputer -sizelimit 0 -includeallproperties -searchroot my.domain.com/MyUserWorkstations
$IPv4Regex = "^(\d{1,3}\.){3}\d{1,3}$"
foreach ($computerobject in $UserWorkstations) {
$computerIP = $NULL
$computerIP2 = $NULL
$computerIP3 = $NULL
$computerserial = $NULL
$computerserial2 = $NULL
$findlastuser = $NULL
$findlastuser2 = $NULL
$lastlogontime = $NULL
$findlastuserFname = $NULL
$findlastuserFname2 = $NULL
$findlastuserLname = $NULL
$findlastuserLname2 = $NULL
$fullname = $NULL
$userlogon = $NULL
$computerName = $computerobject.name
$oldcomputerdescription = $computerobject.description
Write-Host " "
Write-Host "Testing connection to $computerName ..."
$testConnection = test-connection -computername $computerName -count 2 -quiet
Write-Host "Connection is $testconnection"
if ($testConnection -eq $True) {
$Connect = $testConnection
#get IP address(es)
try {
$computerIP = get-wmiobject -class win32_networkadapterconfiguration -filter IPEnabled=TRUE -computername $computerName
$computerIP2 = $computerIP.ipaddress[0]
$computerIP3 = $computerIP.ipaddress[1]
Write-Host = $computerIP2
if ($computerIP3 -match $IPv4Regex){
Write-Host = $computerIP3
}
}
catch [system.exception]{
$connect = $False
Write-Host "Could not connect to $computerName. No IP collected."
}
#get computer serial
try {
$computerSerial = gwmi win32_bios -computername $computerName | select serialnumber
$computerserial2 = $computerSerial.serialnumber.tostring()
}
catch [system.exception]{
Write-Host "Could not get serial for $computerName."
$computerSerial = "Unavailable"
$computerSerial2 = "Unavailable"
}
#get username of currently logged in user
try {
$findlastUser = gwmi win32_computersystem -computer $computerName | select username
$findlastuser2 = ($findlastUser.username).replace("mydomain\","")
}
catch [system.exception]{
Write-Host "Could not get username of logged in user on $computerName"
$findlastUser = "Unavailable"
$findlastUser2 = "Unavailable"
}
#get last logon time of user
try {
if($findlastuser2 -ne $NULL -and $findlastuser2 -notlike "Unavailable") {
#ignore domain controllers in a datacenter due to connectivity stuff
$lastlogontime = get-qadcomputer -computerrole domaincontroller | where { $_.name -notmatch "-COLO"} | foreach {(get-qaduser -service $_.name -samaccountname $findlastuser2).LastLogon } | Measure-Latest
}
}
catch {
if ($lastlogontime -eq $NULL -and $findlastuser2 -eq $NULL){
Write-Host "Could not find a last logon time"
Write-Host "No username available to query"
$lastlogontime = "Unavailable"
}
if ($lastlogontime -eq $NULL -and $findlastuser2 -ne $NULL){
Write-Host "Could not find a last logon time for user $findlastuser"
$lastlogontime = "Unavailable"
}
}
#search AD for the user identified, select first name
try {
$findlastuserFname = get-qaduser $findlastuser2 | select firstname
$findlastuserFname2 = $findlastuserFname.firstname.tostring()
}
catch [system.exception]{
if ($findlastuserFname2 -eq $NULL) {
Write-Host "No first name for user found"
}
}
#search AD for the user identified, select last name
try {
$findlastuserLname = get-qaduser $findlastuser2 | select lastname
$findlastuserLname2 = $findlastuserLname.lastname
}
catch [system.exception] {
if ($findlastuserLname2 -eq $NULL) {
Write-Host "No last name for user found"
}
}
#join the first and last names together if both properties are available
if ($findlastuserFname2 -ne $NULL -and $findlastuserLname2 -ne $NULL){
$fullname = "$findlastuserFname2" + " $findlastuserLname2"
}
elseif ($findlastuserFname2 -eq $NULL -and $findlastuserLname -ne $NULL){
$fullname = $findlastuserLname2
}
elseif ($findlastuserFname2 -ne $NULL -and $findlastuserLname -eq $NULL){
$fullname = $findlastuserFname2
}
else {
$fullname = "Unavailable"
}
#Set the description data format
#With only 1 IPv4 Address
if ($computerIP3 -notmatch $IPv4Regex -or $computerIP3 -eq $NULL){
$newcomputerdescription = "$fullname | $computerIP2 | $computerSerial2 | $lastlogontime"
}
#With 2 IPv4 Addresses
if ($computerIP3 -match $IPv4Regex) {
$newcomputerdescription = "$fullname | $computerIP2, $computerIP3 | $computerSerial2 | $lastlogontime"
}
#If the description data is the same, leave it as it is
if ($newcomputerdescription -eq $oldcomputerdescription){
Write-Host " "
Write-Host "Information for $computerName has not" -foregroundcolor yellow
Write-Host "changed. No edits were made on this object." -foregroundcolor yellow
}
if ($newcomputerdescription -ne $oldcomputerdescription -and $Connect -eq $TRUE) {
set-qadcomputer -identity $computerName -Description $newcomputerdescription
Write-Host " "
Write-Host "Computer description updated for object $computerName" -foregroundcolor yellow
Write-Host "New host information:"
Write-Host "$newcomputerdescription"
}
}
else {
Write-Host "Could not connect to computer $computerName"
Write-Host "No changes made to description for $computerName"
$noconnecterror = "Could not connect to computer $computerName"
$noconnecterror | Out-File $global:logfile -Append -Force
}
}
Write-Host "Processing complete!"
}
CreateLog -erroraction silentlycontinue
WriteDescription -erroraction silentlycontinue
start-sleep -s 3
##END OF SCRIPT
Second Script:
set-location \\myscriptcomputer\c$\somefolder\PSScripts
Add-PSSnapin Quest.ActiveRoles.ADManagement -erroraction SilentlyContinue
$timeoutput = Measure-Command {\\myscriptcomputer\c$\Somefolder\PSScripts\WriteComputerDescriptions.ps1}
cd \\myscriptcomputer\c$\Somefolder\PSScripts\WriteComputerDescriptions
$scriptlog = get-childitem | sort creationtime | select -last 1
$logname = $scriptlog.name
Add-Content c:\somefolder\PSScripts\WriteComputerDescriptions\$logname "`nExecution Time: $timeoutput"
Write-Host "Script complete!"
Start-sleep -s 3
exit
In the results in my environments Active Directory, this works effectively for several hundred objects, but here's a sample of what I see in my log file:
Could not connect to computer computer391 Could not connect to computer computer392 Could not connect to computer computer393 Could not connect to computer computer394 䔊數畣楴湯吠浩㩥ㄠ㨱㘰㈺⸱㜵㤵㐰ഷ
The very last line with the garbled text is what made me think there's a memory-related issue perhaps. If I run my scripts against a container/OU with a much smaller amount of computers, the last line in my log is a time, which is what I would normally expect.
If any seasoned Powershell pros could offer some advice here, I'd really appreciate the help.
Thanks!
I don't know why my comments are not getting added. Anyways, let me just post it here. In order to track the free memory, you just look at its the performance counter.
Here is the powershell command:
Get-Counter -Counter "\Memory\Available MBytes"