CanD's Ms Admin Blog

Microsoft Exchange, Powershell, AD, MOM...

14 Kasım 2007 Çarşamba

Calculating the Total Size of Files with Same Extension under A Folder with PowerShell

As it is always noted PowerShell make a lot of things easier as it makes it easy to deal with large amount of files. Consider a scenario where one wants to see the number .exe files under a specific path including child folders. And also he may ask for the total size of these files!! The answer to this kind of questions comes in no time when you use PowerShell;) Here is how..

Now we will look for exe files under c:\temp

PS C:\ps> dir /temp *.exe


Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp


Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23.09.2007 14:51 7718480 auth finger.exe
-a--- 23.09.2007 15:35 10959456 hda modem.exe
-a--- 23.09.2007 14:45 617392 intel sata.exe
-a--- 23.09.2007 14:51 7086272 intel wireless.exe
-a--- 23.09.2007 15:23 56896928 ms uaa.exe
-a--- 23.09.2007 14:31 837962 sd card.exe
-a--- 23.09.2007 14:50 6732048 soundmax.exe
-a--- 23.09.2007 14:47 7085952 texas media card.exe
-a--- 23.09.2007 15:03 24316376 touchpad.exe
-a--- 23.09.2007 14:40 17221472 video.exe
-a--- 23.09.2007 23:25 37783736 windvd.exe
-a--- 24.09.2007 20:02 337859 XNINSTAL.EXE


Quite easy one!! Here we use a more powershell-looked code the get the same result:

PS C:\ps> gci /temp -Recurse | where {$_.extension -eq ".exe"}


Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp


Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23.09.2007 14:51 7718480 auth finger.exe
-a--- 23.09.2007 15:35 10959456 hda modem.exe
-a--- 23.09.2007 14:45 617392 intel sata.exe
-a--- 23.09.2007 14:51 7086272 intel wireless.exe
-a--- 23.09.2007 15:23 56896928 ms uaa.exe
-a--- 23.09.2007 14:31 837962 sd card.exe
-a--- 23.09.2007 14:50 6732048 soundmax.exe
-a--- 23.09.2007 14:47 7085952 texas media card.exe
-a--- 23.09.2007 15:03 24316376 touchpad.exe
-a--- 23.09.2007 14:40 17221472 video.exe
-a--- 23.09.2007 23:25 37783736 windvd.exe
-a--- 24.09.2007 20:02 337859 XNINSTAL.EXE

Here how we can count them:

PS C:\ps> (gci /temp -Recurse | where {$_.extension -eq ".exe"}).count
12

Lastly the code to calculate the size of files with ".exe" extension

PS C:\ps> gci /temp -Recurse | where {$_.extension -eq ".exe"} | %{$total+=$_.Length}
PS C:\ps> $total
177593933
PS C:\ps> $total/1024/1024
169,366772651672

The last one is to give the result as MB as it is more easy to read!!



And after this instruction here is something more useful. This script will look for all files under the given path including the child folders and gives you a result grouped by extensions. Each extension group lists the number of files and total size of that files with same extension. Lastly it shows the total size and number of all files under the given path and also shows how much time passed since the beginning of the script..



#written by Can Dedeoglu 4 AVEA @ 02.10.2007
#known bug: calculates files with same extension but with different capitals twice!!
#known bug2: if an extension appears only once under the search path, script counts this as none but calculates file size just fine
$time1=[datetime]::now
$ext=gci $args -recurse | where {$_.PSIsContainer -eq $false} | foreach {$_.extension} | sort -Unique
for($i=0;$i -lt $ext.count;$i++)
{
$total=0
gci $args -recurse | where {$_.PSIsContainer -eq $false -and $_.extension -eq $ext[$i]} | foreach {$total+=$_.length}
$count=(gci $args -recurse | where {$_.PSIsContainer -eq $false -and $_.extension -eq $ext[$i]}).count
$countall+=$count
$sizeall+=$total
write-host $ext[$i] -foreground magenta
write-host Total Size: $($total/1024/1024)MB
write-host Total Count: $($count)
write-host -------------------------
}
write-host Total number of all files: $countall
write-host Total size of all files: $($sizeall/1024/1024)MB
$time2=[datetime]::now
write-host Elapsed Time: $($time2-$time1)


Here is the output:



PS C:\ps> .\Get-FileUsage.ps1 /temp
.exe
Total Size: 169,366772651672 MB
Total Count: 12
-- -- -- -- -- -- -- -- -- -- -- -
.msi
Total Size: 12,52001953125 MB
Total Count:
-- -- -- -- -- -- -- -- -- -- -- -
.TXT
Total Size: 0,00594711303710938 MB
Total Count: 2
-- -- -- -- -- -- -- -- -- -- -- -
.vbs
Total Size: 0,0575618743896484 MB
Total Count:
-- -- -- -- -- -- -- -- -- -- -- -
Total number of all files: 14
Total size of all files: 181,950301170349 MB
Elapsed Time: 00:00:00.1716913



Enjoy!!

Watching Emc Xtender's Mailbox Size with PowerShell

Exchange archiving system works perfectly after it's enabled. Archiving is controlled database-based, so you can choose which mail databases to be archived in a storage group. Or incase you want to use archiving for every database at Exchange organization you can easily make it happen by creating a system policy that includes all databases and specify the archive mailbox user.

After enabling that kind of configuration copy of each email transaction is delivered to the mailbox of this archiving user. This is where archiving systems like Xtender joins the game. This archiving systems listens this mailbox and collects each email in their own storage system for future use. With this you can be sure archiving user's mailbox will not be over-sized. I know an Exchange system with this user has a mailbox of nearly 200GB in size because of a problem in archiving server. As you can guess after that trouble had just begin for Exchange admins;)

So it's obvious that this kind of servers and services must be watched closely. You can do it easily with Microsoft Operations Manager but now we will do it with (of course) PowerShell!!



There are two variables in this code; one is the name of the exchange server holding the mailbox of archiving user and the other is the name of the archiving user. Also you can customize the threshold that when an alert will be generated..



$xtender= gwmi -ComputerName exchange_server -namespace root\MicrosoftExchangev2 -Query "Select * from Exchange_Mailbox" | where {$_.MailboxDisplayName -eq "name_of_archiving_user"}
[int]$size=$xtender.size
$totalitems=$xtender.totalitems
if($size -gt 76800)
{
$log="Xtender Critical! Size:$($size /1024)MB***By Number:$totalitems***$(get-date)"
c:\ps\sendsms.ps1 90555255xxxx "$log"
c:\ps\sendsms.ps1 90555255xxxx "$log"
c:\ps\sendsms.ps1 90555255xxxx "$log"
add-content -path "c:\ps\log.txt" -value $log
}
else
{
$log="Xtender OK! Size:$($size /1024)MB***By Number:$totalitems***$(get-date)"
add-content -path "c:\ps\log.txt" -value $log
}



First WMI is used to get information from Exchange by means of the mailbox name. To check other available members of the object by piping the object with "get-member" Here is how you can do it:



PS C:\ps> $xtender= gwmi -ComputerName exc01 -namespace root\MicrosoftExchangev2 -Query "Select * from Exchange_Mailbox"
| where {$_.MailboxDisplayName -eq "emcexadmin"}
PS C:\ps> $xtender | get-member


TypeName: System.Management.ManagementObject#root\MicrosoftExchangev2\Exchange_Mailbox

Name MemberType Definition
---- ---------- ----------
Purge Method System.Management.ManagementBaseObject Purge()
Reconnect Method System.Management.ManagementBaseObject Reconnect(System.String UserLogonName)
AssocContentCount Property System.UInt32 AssocContentCount {get;set;}
Caption Property System.String Caption {get;set;}
DateDiscoveredAbsentInDS Property System.String DateDiscoveredAbsentInDS {get;set;}
DeletedMessageSizeExtended Property System.UInt64 DeletedMessageSizeExtended {get;set;}
Description Property System.String Description {get;set;}
InstallDate Property System.String InstallDate {get;set;}
LastLoggedOnUserAccount Property System.String LastLoggedOnUserAccount {get;set;}
LastLogoffTime Property System.String LastLogoffTime {get;set;}
LastLogonTime Property System.String LastLogonTime {get;set;}
LegacyDN Property System.String LegacyDN {get;set;}
MailboxDisplayName Property System.String MailboxDisplayName {get;set;}
MailboxGUID Property System.String MailboxGUID {get;set;}
Name Property System.String Name {get;set;}
ServerName Property System.String ServerName {get;set;}
Size Property System.UInt64 Size {get;set;}
Status Property System.String Status {get;set;}
StorageGroupName Property System.String StorageGroupName {get;set;}
StorageLimitInfo Property System.UInt32 StorageLimitInfo {get;set;}
StoreName Property System.String StoreName {get;set;}
TotalItems Property System.UInt32 TotalItems {get;set;}
__CLASS Property System.String __CLASS {get;set;}
__DERIVATION Property System.String[] __DERIVATION {get;set;}
__DYNASTY Property System.String __DYNASTY {get;set;}
__GENUS Property System.Int32 __GENUS {get;set;}
__NAMESPACE Property System.String __NAMESPACE {get;set;}
__PATH Property System.String __PATH {get;set;}
__PROPERTY_COUNT Property System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH Property System.String __RELPATH {get;set;}
__SERVER Property System.String __SERVER {get;set;}
__SUPERCLASS Property System.String __SUPERCLASS {get;set;}
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime ScriptMethod System.Object ConvertToDateTime();
Delete ScriptMethod System.Object Delete();
GetType ScriptMethod System.Object GetType();
Put ScriptMethod System.Object Put();



After getting the size of the mailbox, we compare it with our threshold value (in our case it's 75MB). If mailbox size is greater than the threshold a warning message will be logged in c:\ps\log.txt file and this log will be passed to another powershell script to send sms to the admin's cell numbers. In this case log included several things:

1. A critical warning

2. Size of the mailbox

3. The number of mails in mailbox

4. Time of the day



You can schedule this ps1 script easily with Windows Scheduled Tasks. In our case it's created to run this script at every 10 minutes. But it will be annoying if you are also working with desktop of the scheduled task enabled computer. What you will see is the poping up of a powershell screen at every 10 minutes. To avoid from this situation a vbs script is used to hide and execute powershell script. Here is the code:



Dim objShell,objFSO,objFile

Set objShell=CreateObject("WScript.Shell")
Set objFSO=CreateObject("Scripting.FileSystemObject")
strPath="C:\ps\Get-Xtender.ps1"


If objFSO.FileExists(strPath) Then

set objFile=objFSO.GetFile(strPath)
strCMD="powershell -nologo -command " & Chr(34) & "&{" &_
objFile.ShortPath & "}" & Chr(34)
objShell.Run strCMD,0

Else
WScript.Echo "Failed to find " & strPath
WScript.Quit
End If



So to summarize what we have:

1. A .vbs file to start the ps script without pop-up

2. A .ps1 script to watch the mailbox size

3. A .ps1 script to send SMS (not explained here)

4. Windows Scheduled Tasks to start .vbs file at every 10 minutes



Any comment is welcomed! As always it's probably not the best way to do it;) Enjoy!!

Enable RDP from a Remote Location with PowerShell

RDP is enabled or disabled through a Registry key (to be honest mostly System properties GUI is used!!) But what if there is no way of being physically near the computer that you want to rdp. In such a senario System properties GUI is useless as there is no way to reach it. But a simple PowerShell script can make it happen for you. Since PowerShell standart cmdlets don't allow you to change a remote registry value directly, we called a class from .NET for it. The registry key to enable RDP is HKLM:\\System\CurrentControlSet\Control\Terminal Server\fDentTSConnections

Just copy-paste the code below to notepad save as with ps1 extension (i gave the name Get-Rdp.ps1)

$computer=$args
$reg=[microsoft.win32.registrykey]::openremotebasekey('localmachine',$computer)
$regkey=$reg.opensubkey("system\\currentcontrolset\\control\\terminal server",$true)
$regterminal=[system.boolean]$regkey.getvalue('fdenytsconnections')
write-host $computer RDP-> (!$regterminal)

if($regterminal)
{
$choice = read-host "RDP is disabled. Do u want to enable it?[Y/N]"
if($choice = "y")
{
$regkey.setvalue('fdenytsconnections',0)
}
}
write-host RDP enabled (![system.boolean]$regkey.getvalue('fdenytsconnections'))



Below you may see how it works!!

PS C:\ps> .\Get-Rdp.ps1 10.4.62.90
10.4.62.90 RDP-> False
RDP is disabled. Do u want to enable it?[Y/N]: y
RDP enabled True

6 Kasım 2007 Salı

Active Directory User Management with PowerShell Part I

For anyone that is searching for Microsoft's new powerful shell over net it may look like a cliche but it's true: As with so many other topics, Powershell is making your life a lot easier when it comes to Active Directory management. Most of time daily AD administration can be handled easily with AD Users and Computers mmc console. But what if you want to work with another attribute that cant be seen from this GUI? That is when adsiedit.msc join the game. But what if you will work with 1000 thousand objects instead of a few? I heard some say ADModify.exe!! These are great tools to help AD admins to manage their systems but each of them has its limitations and will lead us using too many GUI tools to do one certain job:

AD Management!!

for example to assign an AD user to a variable in powershell
PS C:\ps> $user1=[ADSI]"LDAP://Can Dedeoglu,OU=Users,DC=domain,DC=tr"

to get the value of the variable just call it by name
PS C:\ps> $user1
distinguishedName-----------------{CN=Can Dedeoglu,OU=Users,DC=domain,DC=tr}
As seen from output $user1 is now an ADSI object, completely represanting the user that was identified with its LDAP path. To see the attributes related with that object use this
PS C:\ps> $user1 get-member
TypeName: System.DirectoryServices.DirectoryEntry
Name MemberType Definition---- ---------- ----------accountExpires Property System.DirectoryServices.PropertyValueCollection accountExpires {get;set;}adminCount Property System.DirectoryServices.PropertyValueCollection adminCount {get;set;}authOrigBL Property System.DirectoryServices.PropertyValueCollection authOrigBL {get;set;}badPasswordTime Property System.DirectoryServices.PropertyValueCollection badPasswordTime {get;badPwdCount Property System.DirectoryServices.PropertyValueCollection badPwdCount {get;set;}cn Property System.DirectoryServices.PropertyValueCollection cn {get;set;}codePage Property System.DirectoryServices.PropertyValueCollection codePage {get;set;}company Property System.DirectoryServices.PropertyValueCollection company {get;set;}countryCode Property System.DirectoryServices.PropertyValueCollection countryCode {get;set;}deletedItemFlags Property System.DirectoryServices.PropertyValueCollection deletedItemFlags {get;set;}department Property System.DirectoryServices.PropertyValueCollection department {get;set;}displayName Property System.DirectoryServices.PropertyValueCollection displayName {get;set;}distinguishedName Property System.DirectoryServices.PropertyValueCollection distinguishedName
...
Here is the full list for my evrironment:
accountExpires, adminCount, authOrigBL, badPasswordTime, badPwdCount, cn, codePage, company, countryCode, deletedItemFlags, department, displayName, distinguishedName, dSCorePropagationData, extensionAttribute1, extensionAttribute2, extensionAttribute3, extensionAttribute4, extensionAttribute5, extensionAttribute6, garbageCollPeriod, givenName, homeMDB, homeMTA, instanceType, l, lastLogoff, lastLogon, lastLogonTimestamp, legacyExchangeDN, logonCount, mail, mailNickname, mDBUseDefaults, memberOf, mobile, msExchALObjectVersion, msExchHomeServerName, msExchMailboxGuid, msExchMailboxSecurityDescriptor, msExchPoliciesIncluded, msExchUserAccountControl, mSMQDigests, mSMQSignCertificates, name, nTSecurityDescriptor, objectCategory, objectClass, objectGUID, objectSid, physicalDeliveryOfficeName, primaryGroupID, proxyAddresses, pwdLastSet, sAMAccountName, sAMAccountType, servicePrincipalName, showInAddressBook, sn, telephoneNumber, textEncodedORAddress, title, userAccountControl, userPrincipalName, uSNChanged, uSNCreated, whenChanged, whenCreated
To see how many times this user has logged on the system use "logoncount" attribute:
PS C:\ps> $can.logoncount
4758
another example:
PS C:\ps> $can.department

SYSTEM & DATABASE OPERATION DEPARTMENT

OK, this is a good method if you know the exact LDAP path of the user that you want to work with, but at most this is not the case!!

PS C:\ps>$adsearcher=New-Object System.DirectoryServices.DirectorySearcher("(&(CN=Can*)(objectClass=User))")
PS C:\ps> $adsearcher.findall()

Result is:
LDAP://CN=Can Dedeoglu,OU=Users,OU=AVEA,DC=tt-tim,DC=tr {homemdb, physicaldeliveryofficename, distinguishedname,...

I'll give more examples and details in the next post..

New Born

Hi there, I'm Can Dedeoğlu, working/living in Istanbul/Turkey as system administrator at a GSM company. I'll share my knowledge and experiences on Microsoft systems such as Exchange 2003, Exchange 2007, Active Directory, new born PowerShell and others. Everything written here is provided AS-IS and not guaranteed it's the best way to do it or even it will work for you:) Hope you will find useful materials and hope that this will be a page where I can meet with people in my profession. Cheers!!