Introduction
There are lots of server tasks in Windows Server 2008 that can be done much
faster with Windows PowerShell than with a GUI. What you’ll find in this article
series are ten common server tasks all done on PowerShell.
In this two part mini-series you’ll learn how to:
- Change the local administrator password with
PowerShell
- Restart or shutdown a server with
PowerShell
- Restart a service with PowerShell
- Terminate a process with PowerShell
- Create a disk utilization report with
PowerShell
- Get
10 most recent event log errors with PowerShell
- Reset
access control on a folder with PowerShell
- Get
a server’s uptime with PowerShell
- Get
service pack information with PowerShell
- Delete
old files with PowerShell
1. Changing the local administrator password with
PowerShell.
Let’s assume you’re logged in as a domain administrator on a Windows 7
desktop that belongs to your domain. Now, let’s say you want to change the local
admin password on a remote server in Chicago named CHI-WIN7-22.
After an account password is used for some time, the chances of it getting
exposed gets higher. That’s why you need to change your passwords from time to
time.The first thing to do to change the admin password in question is to create
an ADSI object for the local administrator on that computer. That can be
achieved by typing this in your PowerShell screen: [ADSI]$Admin=”WinNT://CHI-WIN7-22/Administrator”
This will essentially retrieve the admin account on
CHI-WIN7-22 and assign it to an ADSI object named
$Admin. The WinNT monicker in that string is case-sensitive and
is a common source of error, so take note of that. If you want to connect to
another computer, just replace CHI-WIN7-22 with the name of the
computer you want to connect to.
Naturally, you’ll want to know first how long the password has been in use to
determine whether or not the time has come to change it. You can obtain that
information from $Admin by typing in:
$Admin.PasswordAge
That will display the time elapsed since the password of that account was
last changed. However, since the resulting value is expressed in seconds, I
normally divide it by 86,400, which is the number of seconds in a day:
$Admin.PasswordAge.Value/86400
The result will then be the same time elapsed but expressed in days, which I
find more meaningful. If you notice, we used the Value property here. That’s
because the
PasswordAge is actually stored as a collection, and
so we need the value of that collection in order to return a number that we can
perform a division operation on.
Finally, you can change the password by invoking the
SetPassword
method and then using the new password as the argument. For example, if
you want the new password to be
S3cre+WOrd, then type:
$Admin.SetPassword(“S3cre+WOrd”)
Note: After you hit enter, don’t expect any confirmation message because
there won’t be any. Changes will take effect immediately. That’s because what
we’re using here is a method, not a cmdlet. Which means, unlike with cmdlets,
SetPassword has no support for a
-whatif or a
-confirm.
That’s all there is to it. Let me now show you the steps we’ve discussed here
in theory on an actual PowerShell:
2. Restarting or shutting down a server with
PowerShell
Let’s now move on to the task of restarting or shutting down a server using
PowerShell. Just like the first task, we’re still going to assume you’re logged
in as a domain administrator on a Windows 7 machine that belongs to your
domain.
For these tasks, we’ll be using a couple of WMI-based cmdlets,
Restart-Computer and
Stop-Computer. Although
we won’t be showing them here, it’s worth mentioning that these cmdlets accept
alternate credentials. Alternate credentials allow you to specify a user account
other than the one you are already logged into so that you can perform actions
that that (alternate) account has permissions for.
Another thing that’s nice about these cmdlets is that you’ll be able to make
use of
-whatif and
-confirm. That means, if
you want to do a restart or a shutdown, you’ll have a way of making sure you’ll
be doing it on the computer you intend to do it on. This can come in handy if
you want to perform restarts or shutdowns on a number of computers. You can just
pipe a list or group of computers to these cmdlets.
To restart a remote computer or computers, the basic syntax is:
Restart-Computer -ComputerName <string[ ]>,
wherein
-ComputerName <string[ ]> is a string array
that can be comprised of the name of a single computer or the names of multiple
computers.
Stop-Computer uses practically the same syntax. So
for example, if you want to restart two computers named CHI-DC02 and CHI-FP01,
the command would be:
Restart-Computer “CHI-DC02”, “CHI-FP01”
Here’s an actual PowerShell screenshot wherein we used the
-whatif argument. You use a
-whatif if you
simply want to simulate what would happen if you would execute the command in
question.

That was pretty straightforward. Let’s now try a more sophisticated example.
Let’s assume you have a list of computers in a file named
servers.txt. You can use the
Get-Content
cmdlet to retrieve the contents of that text file, like this:

So, if you have a bunch of computers that you want to restart on a regular
basis, you can list down the names of those computers in a text file. Then each
time you need to restart them, you simply use the
Get-Content
cmdlet. Here’s how we used
Get-Content and
Restart-Computer in a real-world scenario:

First, we got the content from the text file using
Get-Content. Then, because we wanted to prepare for the
eventuality that some computers would be offline, we piped the list to a
where statement for testing. In the
where
statement, we ran
test-connection, which is basically
a
ping on each computer.
The
-quiet returns either
true or
false, while
-count 2 means each computer will
only be pinged twice. Those computers that were successfully pinged twice, were
then passed along the pipeline.
Next, we used a
foreach. Specifically, the objective was
that: for each name that came out of the ping test, a green-colored message
would be written saying that that computer was “
Restarting”.
The
$_ stands for the current object in the pipeline. Next, the
Restart-Computer cmdlet was called to restart each computer
that could be pinged. We also used the
-force parameter to kick
off anyone logged on.
Finally, we used
-whatif again to see what would happen
without having to actually restart those computers.
3. Restarting a service with PowerShell
Restart-Service is the cmdlet used for restarting a service.
Although this cmdlet does not have a built-in mechanism to connect to a remote
computer, PowerShell Remoting can be enabled so that you can execute it locally
via remoting on the remote computer. This can come in handy when you want to
restart a service on a group of computers.
To restart a service locally, simply say:
Restart-Service
“service”, wherein “service” is the name of the service you want to
restart. On the other hand, if you want to restart a service on one or more
remote machines, then you can use the
Invoke-Command cmdlet and
PowerShell Remoting.
In the PowerShell screenshot below, you see two instances wherein we executed
the
Restart-Service cmdlet to restart the service called
wuauserv, which is the Windows Update service. In the first
instance,
Restart-Service is executed locally. But in the
second instance, it is executed on a remote database server named
CHI-DB01 with the help of the
Invoke-Command.

By default,
Restart-Service doesn’t write any objects in the
pipeline unless you use
-passthru. So the additional
information you see at the bottom (Status, Name, etc.) is a result of using
-passthru. If the service runs on multiple computers and you
want to restart the service running there as well, just add more computer names
in a comma-separated list.
Another way to do that same task is by using WMI. First, you create a WMI
object:
gwmi is the alias for
Get-WmiObject.
Let me show you first the methods of this object. To do that, we’ll pipe the
object to
Get-Member (alias is
gm).

If you notice, there is no method for restarting ther service. That means, we
will have to stop the service using the
StopService method and
then start it again using the
StartService method.
Here’s how you stop the service using the object’s
StopService
method. The parenthesis indicates it’s a method. If you get a
ReturnValue of 0, that means the service stopped successfully.
In case you get another value, you can research what that value means by reading
the MSDN documentation for the Win32 service class.

To fire the service up again, you use the
StartService
method.

You can verify by executing the
get-service command for that
computer.
Get-service allows you to connect to a remote
computer, so you can simply get that service from the target computer to verify
if it is in fact running there.
4. Terminating a Process with Powershell
Another task that’s commonly done on a server is terminating a process. To
terminate a process, you use the
Stop-Process cmdlet. Again,
this can be executed locally or, if you want to stop a process on a remote
system, you can use
Stop-Process along with
PowerShell
Remoting.
There are two ways of terminating a process using the
Stop-Process
cmdlet.
The first one is pretty straightforward. You just run the
Stop-Process command and then pass to it either the name of the
process or its corresponding ID. In the screenshot below, the name of the
process being killed is ‘
Calc’ (which is really just the
Windows Calculator). Note that
Calc is running locally in this
example.

The second involves using the
Get-Process cmdlet to get one
or more processes and then piping them to
Stop-Process to kill
all those processes at the same time. In the screenshot below, the process being
killed is
Notepad. Note that
kill is an alias
of
Stop-Process. Again, just like
Calc in the
previous example,
Notepad is running locally.

Let’s now move on to an example where we have a process running remotely.
First, let’s fire up a process to kill. So here, we’re starting
notepad on a remote computer named
chi-fp01.

Next, let’s check whether the process is actually running. For this purpose,
we use
ps, which is an alias for
Get-Process.

Ok. Now that we have a remote process to kill, let’s go ahead and kill it.
Like what we did in our discussion on
Restarting a Service,
we’ll use
Invoke-Command and
PowerShell
Remoting to run the
Stop-Process expression on the
remote server
chi-fp01.
See how the
Get-Process alias (
ps), which
is running in the script block, pipes the process to the
Stop-Process
alias (
kill)
.
5. Creating a Disk Utilization Report with
PowerShell
As admins, we often need to keep track of how much disk space is being used
on our servers. We can accomplish this using WMI and the Win32_LogicalDisk
class, which will give us information such as the Device ID, the size of the
drive, free space, and a few other bits of information.
Using WMI, we can query local or remote computers. We can also perform those
queries on either a single or multiple machines. In addition, we can: export the
data we query to a CSV file or a database; create a text-based or an HTML-based
report; or simply display the output to the screen.
Here’s a sample command using WMI on a local computer.
Get-WmiObject win32_logicaldisk -filter “drivetype=3” | Out-File
c:\Reports\Disks.txt
We use the
GetWmiObject cmdlet to return information from
the
Win32_LogicalDisk class. Then we employ the
-filter
to return only information related to
drivetype=3,
which stands for fixed logical disks like the
c: drive. That
means, information regarding USB drives and network drives are not to be
included.The returned information is then piped to a text file named
Disks.txt.
Here’s a similar example done in an actual PowerShell where we could see an
actual output. Note that we are using aliases to shorten the command. Also, in
this example, we specified that the output would include the device ID, disk
size, the free space, and the system name.

While there’s certainly nothing wrong with that output, it sure could use a
couple of improvements. For example, you might want to display the size and free
space in Gigabytes instead of bytes. We can actually get a more elegant output
by adding a few extra steps. Let me show you how.
For this purpose, we’re going to create a function named
Get-DiskUtil. Although the succeeding example is going to show
you how to do things interactively in the shell, you can actually put this
function in a script file, load it into your profile, or load it to your other
scripts so that you can use it again later on.
Here’s the function I’m talking about:

Let’s dissect that function now.
The function is going to take a computer name as its parameter and it will
default to the local computer name.

Now we use the
Process script blocks that this computer name
property can be piped-in to the function. If it gets a piped-in value ($_), then
it’s going to set the computer name variable to that piped-in value. Otherwise,
it will take the computer name that gets piped-in as a parameter.

Next up is the
GetWmiObject expression.

The output of that expression is piped to the
Select-Object
cmdlet (represented by its alias,
Select). We then
make use of a hashtable to create a custom property called
Computername. This basically renames the
SystemName of the current object ($_) to
Computername. The
DeviceID is passed along as
is.

We then deploy a couple more hashtables. The first one takes the
Size property, divides it by 1GB, expresses the result into two
decimal points, and renames the property to
SizeGB. The second
one takes the
Freespace property and does practically the same
thing to it.

Next, we create a new property called
UsedGB, which doesn’t
exist in WMI. It simply takes the difference between the
Size
and
FreeSpace properties and divides the result by 1GB.

Finally, we also create another property called
PerFree,
which stands for “percent free”. This shows the free space as a fraction of
total disk size expressed in percentage. And that completes the function.

Here’s the function in action wherein we passed to it the name of the
computer, piped the output to
Format-Table (or
ft), and set the final output to auto-size using
-auto.

While all this looks nice and pretty, there’s still a lot more that we can
get from this function. So let’s say that on a weekly basis, you need to get a
disk utilization report of all the servers in your environment. Here are a
couple of different ways you can work with this data.
The first thing we’re going to do is to save the results of our expression to
the variable
$data. That’s so we don’t have to type in the
command repeatedly. Next, we pipe the results to the
where
object, do the ping tests (pinging it twice when it can be pinged), and
then pipe the computer name to our newly-created
Get-DiskUtil
function.
You’ll know that the command is done executing when you get the prompt
back.

That would mean the data has already been stored in
$data.
You can then pipe the information in
$data to sort by
computername and then set it to auto-resize. You can also send
that information to
Out-Printer or
Out-File.

Similarly, if you want to load that information to a SQL database or an Excel
spreadsheet, you can convert the data to a CSV file like this:

Later on, if you import that CSV file, you will be able to obtain a snapshot
of the disk utilization status of those disks right at the time the command is
run.

Here’s a portion of that snapshot:

As a final example, let me show you how to create an HTML report that perhaps
you will want to put on your Internet server to show disk utilization. So that,
as an IT admin, you can go ahead and take a quick peek at your disk utilization
status even while you’re outside the office.
So again, you start by taking $
data and pipe it to
Sort Computername. You then pipe the result to the
ConvertTo-HTML cmdlet. You also give it a title and specify a
CSS path. The CSS part is needed because
ConverToHTML does not
do any formatting. So if you want your report to look pretty you’ll need that
CSS file. Finally, you need to send the output to a file.

Now that your file’s ready, you can then look at the file by using the
start command.

Here’s a sample of that HTML report.

Remember that the values on this report are up-to-date.
6. Getting 10 most recent event
log errors
Every morning, you may have to go through your event logs to find the 10 most
recent errors in the system event log on one or more computers. You can easily
accomplish that task with PowerShell using the
Get-EventLog
cmdlet.
All you need to specify is the name of the log and the entry type. A typical
command for this particular task would look like this:
Here, the name of the log is ‘system’ and the entry type is ‘Error’. So
PowerShell is going to fetch the 10 most recent error entries from the system
log. This command is issued to a local computer, so we don’t have to specify a
computer name.
Notice that the messages aren’t shown in their entirety. Let’s modify the
command a bit so you can see those messages.

We simply piped the output of the previous command to
ft,
which is an alias for
Format-Table, and then asked the table to
display the following properties:
Timewritten,
Source,
EventID, and
Message.
We also added the
-wrap and
-auto to make the
output prettier.
-wrap enables text wrapping, while
-auto enables auto-sizing.
Here’s a portion of that command’s output:
Let’s create yet another version of that command. This one sorts the
properties by
Source and then groups them. The final output is
piped to
more so that the display will pause one screen size at
a time and not scroll all the way down.

Here’s a portion of the output:

Notice how the items are grouped by source. The first set of information have
EventLog as their source, while the second set have
Microsoft-Windows-GroupPolicy. Notice also the
-- More
-- indicator at the end, which tells the user to press a key in order
to view more information.
All those
Get-EventLog commands we showed you were done on a
local computer. Let’s now see how we can do this remotely.
For example, let’s say I want to see the 5 most recent errors on my domain
controllers in my Chicago office. The computer names are
chi-dc01 and
chi-dc02. Let’s assume that I
would like to sort and group the output by
Machine Name. I
would also like to show the following properties:
Timewritten,
Source,
EventID, and
Message.
Again, I will add
-wrap,
-auto, and
more to get a more visually appealing look.

Here’s a portion of the output.

If you still recall what we did in task #5 of this article, you can pipe the
output of this command to an HTML file and put the report on an Internet server.
Anyway, there are lots of things you can do with this output. The important
thing is that you now know how to get the needed information using the
Get-EventLog cmdlet in PowerShell.
7. Resetting access control on a
folder
There may be instances wherein the NTFS permissions of a folder are not set
the way they need to be. If this happens, you will want to reset the access
control on that folder. To accomplish that, you can use the
Set-Acl
(Set-ACL) cmdlet.
The easiest approach would be to use
Get-Acl to retrieve the
ACL from a good copy and then copy that ACL to the problematic folder. That will
replace the existing ACL. Although it is also possible to create an ACL object
from scratch, the first method (i.e., copying from a good copy of the ACL) is
the recommended option, and that’s what we’re going to show you here.
Let’s say we have a file share called
sales in a computer
named
CHI-FP01, and that file share has a ‘good’ copy of the
ACL. To copy the ACL of
sales and then store it in a variable
named
$acl, you execute this command:

Let’s have a look at the information inside that ACL:

See that
Access property at the right? That is actually
another object. To see the contents of that object, just use this command:

Here are some of its contents:

As you can see, it is actually a collection of access control entries. If you
only want to see identity references whose names match with “Sales”, enter the
following command:

Now, if we use the same command to view the contents of the
Access property belonging to a newly created file share named
chicagosales, we get nothing. Note that we are using a
shorthand notation here:

One possible reason why we aren’t getting any values is maybe the share was
set up but the NTFS permissions were not properly provisioned.
Obviously, the solution to this problem would be to copy the ACL from our
‘good’ file share and apply it to our ‘bad’ file share. But first, we need to
take the current NTFS permissions of the
chicagosales file
share and save them to an XML file. That way, if something goes wrong, we can
simply roll-back by re-importing that XML file and use
Set-acl
to set those permissions back.

Once that’s taken cared of, you can then go ahead and apply a
Set-Acl
command on chicagosales using $
acl, which is just the
ACL copied from our ‘good’ file share.

To verify whether we’ve succeeded, we can apply the same command we used
earlier to display identity references whose names matched with “Sales”:

So now, the
chicagosales NTFS permissions are the same as
the
sales permissions. That’s the easiest way to manage
permissions and is one way to quickly address access control issues.
8. Getting a server’s uptime
You’re boss might want to be updated regularly regarding your server’s
uptime. To get the information you need for this task, you use the WMI
Win32_OperatingSystem class. This will return the value you need, and it works
locally and remotely. The property you’ll want to look at is the LastBootUpTime.
However, since it comes in a WMI format, you’ll want to convert it later to a
more user-friendly date-time object.
Let’s start with an example using a local computer running Windows 7.
First, let’s save the results of a
GetWmiObject expression
to a variable named $
wmi.

So now, $
wmi will have some properties we can work with. The
properties you will normally want to work with are the
CSName
(computer name)
and
LastBootUpTime.

As mentioned earlier, the
LastBootUpTime is a WMI timestamp,
which is not very useful. So we need to convert that. Let’s save the converted
value to a variable named $
boot.

We used the
ConverToDateTime method, which is included on
all the WMI objects that you get when you run
GetWmiObject. The
parameter you pass to that method is the
LastBootUpTime
property of the WMI object $
wmi.
If you show the value of $
boot, you’ll get something like
this:

That is clearly a more useful piece of information than the original form of
the
LastBootUpTime. To find out how long that machine has been
running you just subtract $
boot from the current date/time,
which can be obtained using
Get-Date.

The result is a TimeSpan object. You can get a more compact result by
converting that object to a string using the
ToString().
Practically every object in PowerShell is equipped with a
ToString() method.

The result above tells us that the machine has been running for 2 days, 5
hours, 46 minutes, and so on.
Let’s now put everything we learned here into a function called
get-boot. Let me show you the function first in its
entirety.

The function has a parameter that takes a computer name and defaults to the
local computer name.

It also has a
Process script block so computer names can be
piped to it. Basically, if something is piped-in to it, the variable
$
computername will be set to the piped-in value. Otherwise,
what will be used is whatever was passed as the parameter for computername.

Included in the
Process script block is the
GetWmiObject expression specifying the remote computer
name.

There are also a couple of hashtables. The
CSName property
is not so user-friendly, so it is replaced with a new property called
Computername. There’s also a property called
LastBoot which contains the value of
LastBootUpTime
converted using the
ConvertToDateTime() method. And
then there’s one more property called
Uptime, which is a
TimeSpan object that shows how long the machine has been
running.

If we run this locally (i.e., we don’t have to specify a computer name), the
function defaults to the local computer name. Here’s the output:

Just like what we did in item #2 of this article (“
Restarting or
shutting down a server”), you can save the names of your servers in a
text file, process only those that can be pinged, and then pipe those names to
the
get-boot function.

That last screenshot shows you a list of remote computers and their
corresponding last boot up time as well as their total uptime.
9. Getting service pack information
There are a couple of reasons why you would want to obtain service pack
information of your servers. One reason is that you may be in the process of
rolling out an upgrade and you need to find the computers that require a
particular service pack. Another reason is that you may be doing an inventory or
audit of your computers and part of the data that you would like to get is the
level of service pack they are at.
Again, you can accomplish this using WMI and the Win32_Operating System
class. There are several properties you may want to look at. This would include:
the ServicePackMajorVersion, which is just an integer indicating the version
pack such as 1, 2, or zero; the ServicePackMinorVersion, which is rarely seen
but is there; and the CSDVersion, which will give you a string representation
such as “Service Pack 1”.
If you have been reading this article from the beginning up to this point,
you should know by now that you can use WMI to get a lot of information from
your computers in Windows PowerShell. So again, we’ll employ
Get-WmiObject and the
Win32_operatingsystem
class. The properties you’ll most likely be interested with are the
CSName (computer name),
Caption (the operating
system)
, CSDversion, and the
ServicePackMajorVersion.
Here’s a typical expression using all that.

As shown from the screenshot, this Windows 7 box is not running any service
pack, so the ServicePackMajorVersion is zero, while the CSDVersion is blank.
Let’s now deploy our time-honored practice here of creating a function. Let’s
create a function named
Get-SP. As usual, we’ll take a
parameter of the computer name, which will default to the local computer.

Again, we use a
Process script block. So if a computer name
is piped-in, the variable $
computername will be set to that
piped-in object. The main part of this function is the
Get-Wmiobject/Win32_operatingsystem class expression.
Just like before, we deploy a couple of hashtables. We take the
CSName property and assign that to a property called
ComputerName, which is much easier for a user to understand.
In the same manner, instead of using the
Caption property, we
use
Operating System. And instead of using
CSDVersion, we use
SPName. Lastly, instead of
using
ServicePackMajorVersion, which is quite a mouthful, we
simply use
Version.
Of course, you can assign any property name you deem most suitable in your
case.

Here’s the complete function along with a sample output when we run it
locally:

So now, we’re ready to grab our list of computers from our text file, only
deal with those we can ping, and pipe-in each of those computer names to our
newly-created
get-sp function. Here’s the result:

You can see that CHI-DC02 is missing Service Pack 1, which has been released
for Server 2008 R2. So I should, at some point, put in my project plan to update
the Service Pack on that computer.
10. Deleting old files
The last common task we’re featuring here is the task of deleting old files.
This is something you may need to do in cleaning up a file server or a user’s
desktop. You may need to find files in those computers that are older than some
date and delete them. To accomplish this, we’ll be using the
Get-ChildItem cmdlet. It has an alias called
dir, which is a term you’re more familiar with.
The best way to implement this task is to compare the
LastWriteTime
property on a file or folder object to some date-time threshold. If the
LastWriteTime is beyond that date-time cutoff, then that’s a
file you would want to delete. Just so you know, there’s also a
LastAccessTime property but I rarely use that.
While
LastWriteTime indicates when the file was last
modified,
LastAccessTime could be populated or changed by
system utilities such as antivirus software or a defrag utility. Thus,
LastAccessTime is not a good representation of the time when
the file was last accessed by an actual user.
Once you find the files you’re looking for, you can pipe them to
Remove-Item. Because
Remove-Item supports
-WhatIf and
-Confirm, you can first run the
command with those parameters, save the result to a text file, show it to your
boss for approval, and then go ahead with the final deletion process.
Although it is possible to use a one-line pipeline expression in PowerShell
to find particular files for deletion, I find this task best done using a
script. That way, you can add some logging capabilities and support for
whatif because if you’re deleting files, you really need to
make sure you’re deleting the files you really intend to delete.
Here’s an example script file I wrote that does this job quite well. It’s
available on the disk, so you can view the complete script from there. Look for
the file called
Remove-OldFiles.ps1. Here’s a portion of that
script:

It’s actually an advanced script, which uses cmdlet binding that’s set to
SupportShouldProcess=$True. That means, if you specify
-whatif when you run the script,
-whatif will
be picked up by
Remove-Item, which supports
-whatif.
Notice the parameter named $
Cutoff. That is the cutoff date.
The default value is 180 days from the current date but you can specify another
value and it will be treated as a date-time object.
The meat of the command is this:

It will do a recursive directory listing of the specified path. More
specifically, it will seek out all the files where the
LastWriteTime
is less than $
cutoff. Then it will save the files
that meet that criteria to a variable called
files using the
common parameter
-outvariable. Finally, any file that the
where object picks up will be piped to
Remove-Item, which will recursively go through and delete the
files if it can.
Assuming files that meet the conditions for deletion are found, an xml file
will then be created and stored in the current directory. The file will be given
the file name
Delete-yyyyMMddhhmm.xml, wherein ‘yyyyMMddhhmm’
is the current timestamp expressed in year-month-day-hour-minute. This will give
you an audit trail for the files that are deleted.
Here’s the code snippet responsible for that:

So those are the main parts of the script. Let’s see it in action. First,
let’s get a cutoff date that’s 270 days from the current date.

Next, we run the script. Now, let’s say I want to clean up the public
directory of my file server in Chicago. The server’s name is
chi-fp01 and I want to delete all files older than the
specified cutoff date.
Here’s the command, along with the result notifications.

Notice that you can see the path of the xml file that was exported, so you
can check it out later if you want. For the meantime, let’s just see the first
four files that were deleted. To do that, let’s just import the contents of the
xml file to a variable named $
data and then view the first four
items in $
data.

If you look at the dates of those files, you’ll see how old they really
were.