Basics with Windows PowerShell V2 by Prometheus MMS - HTML preview

PLEASE NOTE: This is an HTML preview only and some elements such as links or page numbers may be incorrect.
Download the book in PDF, ePub, Kindle for a complete version.
  1. DATES AND TIMES

The following articles provide a brief introduction to working with dates and times in Windows PowerShell; these tasks include such things as retrieving the current date and time, and performing date arithmetic. As is so often the case with Windows PowerShell, the code snippets found in these articles can either be included within a Windows PowerShell script or typed directly into the Windows PowerShell console.

1.1 Changing a Computer’s Date and Time

Before explaining how to use the Set-Date cmdlet we should note that this is a cmdlet you should use with care. For example, if you’re in an Active Directory environment your workstation times must be closely synchronized with your domain controller times; if they aren’t, you might not be able to log on to the domain. Computer times are often assigned using an automatic time service; in that case, you probably don’t need to (and probably shouldn’t) set dates and times by hand. However, if you do have a need to set dates and times manually then Set-Date provides an easy way to do so.

One way to change the date/time on a computer is to use the -date parameter followed by the new date and time. For example, suppose you want to set the date and time to 8:30 AM on June 1, 2006. Here’s how you do that:

“Set-Date -date "6/1/2006 8:30 AM”

Need to set the clock ahead exactly two days? This command uses the Get-Date cmdlet and the AddDays method to advance the clock two days:

Set-Date ( Get-Date).AddDays (2)

Other methods that can be used here include AddHours, AddMinutes, and AddSeconds. Need to set the clock back 1 hour due to Daylight Saving Time? Then simply set the clock back -1 (minus 1) hours, like this:

Set-Date ( Get-Date).AddHours (-1)

 

1.2 Listing Date and Time Information

 

 

As you might expect, the Get-Date cmdlet enables you to retrieve the current date and time. As you might also expect, there are a few other interesting tricks you can do with Get-Date, some of which we’ll show you momentarily.

Let’s start with the simplest scenario first. If all you want is the current date and time then simply call Get-Date without any additional parameters:

Get-Date

In return, you’ll get back something similar to this:

Wed May 10 10:07:25 2006

Ah, but suppose you want only the date, not the date and the time? Then just use the displayhint parameter and specify date:

Get-Date -displayhint date

Or, if you’d prefer just the time:

Get-Date -displayhint time

You can also use Get-Date to create a date-time object for any date/time. For example, this command creates a variable named $A that maps to 12:00 AM on May 1, 2006:

$A = Get-Date 5 / 1/2006

What’s that? You need to map $A to 7:00 AM on May 1, 2006? Why not:

$A = Get-Date "5/1/2006 7:00 AM"

Get-Date also includes a number of methods for doing some handy-dandy date arithmetic:

Add Seconds

Add Minutes

Add Hours

Add Days

Add Months

Add Years

Need to know the date/time 137 minutes from now? This command will show you: ( Get-Date).AddMinutes (137)

1.3 Performing Date Arithmetic

The New-TimeSpan cmdlet provides a way to do date arithmetic within Windows PowerShell. For example, this command tells you the number of days between today’s date and New Year’s Eve 2006:

New-TimeSpan $(Get-Date) $(Get-Date -month 12 -day 31 -year 2006)

When this command was run on May 10, 2006 we got back the following:

 

Days : 235

Hours : 0

Minutes : 0

Seconds : 0

Milliseconds : 0

Ticks : 203040000000000

TotalDays : 235

TotalHours : 5640

TotalMinutes : 338400

TotalSeconds : 20304000

TotalMilliseconds : 20304000000

 

Note. All those who knew that there were 20,304,000,000 milliseconds between May 10, 2006 and December 31, 2006 please raise your hands.

To use New-TimeSpan you just need to pass it a pair of date-time values. The best way to do that is to use the Get-Date method; that helps ensure that you get a pair of date-time objects that New-TimeSpan can work with. For our first date, we simply use the Get-Date cmdlet without any additional parameters (note that the cmdlet must be enclosed in parentheses):

$(Get-Date)

For our second date we also call Get-Date, but we tacked on the -month, -day, and -year parameters, along with the appropriate values:

New-TimeSpan $(Get-Date) $(Get-Date -month 12 -day 31 -year 2006)

What if you need to know how long it is until a more specific time, such as 11:30 PM on December 31st? As usual, no problem: just include the -hour and the -minute parameters along with the appropriate values (for the hours, use the 24-hour time format). In other words:

New-TimeSpan $(Get-Date) $(Get-Date -month 12 -day 31 -year 2006 -hour 23 -minute 30)

 

2. FILES AND FOLDERS

The following articles provide a brief introduction to carrying out file system management tasks by using Windows PowerShell; these tasks include such things as creating, renaming, copying, and deleting files and folders. As is so often the case with Windows PowerShell, the code snippets found in these articles can either be included within a Windows PowerShell script or typed directly into the Windows PowerShell console.

Want to a copy a file or folder to a new location? Then you want the Copy-Item cmdlet. For example, here’s a command that copies the file Test.txt from the C:\Scripts folder to the C:\Test folder:

Copy-Item c:\scripts\test.txt c:\test

Want to copy all the items in C:\Scripts (including subfolders) to C:\Test? Then simply use a wildcard character, like so:

Copy-Item c:\scripts\* c:\test

You’re way ahead of us: yes, this next command copies only the .txt files in C:\Scripts to C:\Test:

Copy-Item c:\scripts\*.txt c:\test

Finally, this command puts a copy of the folder C:\Scripts inside the folder C:\Test; in other words, the copied information will be copied to a folder named C:\Test\Scripts. Here’s the command:

Copy-Item c:\scripts c:\test - recurse

Incidentally, the -recurse parameter is absolutely crucial here; leave it out and a Scripts folder will be created in C:\Test, but none of the files and folders in C:\Scripts will be copied to the new location; you’ll create a C:\Test\Scripts folder, but there won’t be anything in it. Copy-Item Aliases

cpi cp

copy

 

2.1 Creating a New File or Folder

 

New-Item is a quick and easy way to create a new file or folder on your computer. For example, suppose you want to create a new directory named Windows PowerShell within the C:\Scripts folder. To do that call New-Item along with: 1) the full path to the new folder; and, 2) the new item type (which you can specify using the -type parameter and the value directory). The command in question will look like this:

New-Item c:\scripts\Windows PowerShell -type directory

To create a new file follow the same procedure, specifying the full path name but this time setting the type to file. This command creates the file C:\Scripts\New_file.txt:

New-Item c:\scripts\new_file.txt -type file

If the item you are trying to create already exists you’ll get back an error message similar to this:

New-Item : The file 'C:\scripts\new_file.txt' already exists.

However, you can override the default behavior by including the -force parameter:

New-Item c:\scripts\new_file.txt -type file - force

If you use -force the existing file New_file.txt will be replaced by the new, empty file.

And speaking of new, empty files, you can also use the -value parameter to add some data to your new file. This command adds the phrase This is text added to the file at the same time it creates New_file.txt:

New-Item c:\scripts\new_file.txt -type file -force -value "This is text added to the file"

New-Item Aliases

Ni

2.2 Deleting a File or Folder (Or Other Type of Object)

The Remove-Item cmdlet does exactly what the name implies: it enables you to get rid of things once and for all. Tired of the file C:\Scripts\Test.txt? Then delete it:

Remove-Item c:\scripts\test.txt

You can also use wildcard characters to remove multiple items. For example, this command removes all the files in C:\Scripts:

Remove-Item c:\scripts\*

There is one catch, however. Suppose C:\Scripts contains subfolders. In that case, you’ll be prompted as to whether or not you really do want to delete everything in the Scripts folder:

Confirm

The item at C:\test\scripts has children and the -recurse parameter was not specified.

If you continue, all children will be removed with the item. Are you sure you want to continue? [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):

Is there a way to bypass this prompt? Yep; just tack the -recurse parameter onto the end of your command:

Remove-Item c:\scripts\* - recurse

Here’s an interesting variation. Suppose the Scripts folder contains a bunch of files and you’d like to delete them all. Wait: maybe not all, maybe you’d like to leave any .wav files. No problem; just use the -exclude parameter and indicate the file types that should be excluded from the deletion:

Remove-Item c:\scripts\* -exclude *.wav

What’s that? Now you’d like to remove just .wav and .mp3 files, leaving all other file types alone? All you had to do was ask (and use the -include parameter):

Remove-Item c:\scripts\* -include .wav,.mp3

As you’ve probably figured out, if you use the -include parameter the cmdlet will act only on those items specified as part of that parameter. (And, yes, you can specify multiple items; just separate items using commas.) By contrast, if you use the -exclude parameter those items will be exempt from the cmdlet actions.

And yes, if you want to get really fancy you can use both -include and -exclude in the same command. What do you suppose will happen when we run this command?

Remove-Item c:\scripts\* -include *.txt -exclude *test*

You got it: all the .txt files (as indicated by the -include parameter) in the C:\Scripts folder will be deleted, except for any files that have the string value test anywhere in the file name (as indicated by the -exclude parameter). Try some different variations, and it will soon make perfect sense.

Incidentally, the Remove-Item cmdlet has a -whatif parameter that doesn’t actually remove anything but simply tells you what would happen if you did call Remove-Item. What do you mean that doesn’t make any sense? Here, take a look at this command:

Remove-Item c:\scripts\*.vbs – whatif

 

If we run this command, none of the .vbs files in the folder C:\Scripts will be removed; however, we will get back information like this, which lets us know which files would be removed if we called Remove-Item without the -whatif parameter:

What if: Performing operation "Remove File" on Target "C:\scripts\imapi.vbs".

What if: Performing operation "Remove File" on Target "C:\scripts\imapi2.vbs".

What if: Performing operation "Remove File" on Target "C:\scripts\methods.vbs".

What if: Performing operation "Remove File" on Target "C:\scripts\read-write.vbs

".

What if: Performing operation "Remove File" on Target "C:\scripts\test.vbs".

What if: Performing operation "Remove File" on Target "C:\scripts\winsat.vbs".

In addition, you can remove things other than files and folders. For example, this command gets rid of an alias named show:

Remove-Item alias:\show

Make a note of how you specify the location: alias:\. That’s standard notation for all Windows PowerShell drives: the drive letter followed by a colon followed by a \. For example, to switch to the Windows PowerShell drive for environment variables use this command:

Set-Location env:\

Remove-Item Aliases

ri

rd erase

rm

rmdir del

2.3 Moving a File or Folder

You know how it is: as soon as you have everything set up just perfect, you’ll invariably want (or need) to change things. The files you put in the C:\Scripts folder? Turns out they should really be in C:\Test. Or maybe just the .zip files should be in C:\Test. Or maybe - well, you get the idea. Can you use Windows PowerShell to move items from one location or another? Let’s put it this way: if you couldn’t, it would be pretty silly to have a cmdlet named Move-Item.

Let’s take a look at a very simple example: moving a single file from one folder to another. To do that, call Move-Item followed by, in order, the path to the file to be moved and the location to move it to. For example, this command moves the file C:\Scripts\Test.zip to C:\Test:

Move-Item c:\scripts\test.zip c:\test

Nothing to it, huh? Because Move-Item accepts wildcards you can easily move all the .zip files in C:\Scripts to C:\Test:

Move-Item c:\scripts\*.zip c:\test

And so on.

By default, Move-Item will not overwrite any existing files in the target folder. For example, suppose you’re trying to move a file named Test.zip from C:\Scripts to C:\Test. However, C:\Test already contains a file named Test.zip. In that case the move will fail … unless you include the force parameter, which instructs Move-Item to overwrite existing files. This command will move Test.zip to the Test folder, even if the file C:\Test\Test.zip already exists:

Move-Item c:\scripts\test.zip c:\test - force

Also by default, you need to specify only the folder name (e.g., C:\Test) when indicating the new location for the item. However, you do have the option to specifying a complete path when moving an item, which will effectively move the item and then rename it. For example, this command moves the file C:\Scripts\950.log to the C:\Test folder. Note, however, the actual target location: C:\Test\MyLog.log. That means the command will move the file 950.log, and then rename it MyLog.log.

Here’s what the command looks like:

Move-Item c:\scripts\950.log c:\test\mylog.log

Move-Item Aliases

mi

mv

move

 

2.4 Renaming a File or Folder

What can you do with the Rename-Item cmdlet? Well, one thing you can do is rename files or folders; all you have to do is call Rename-Item followed by two parameters:

The current path for the file or folder.

The new name for the file or folder.

For example, this command renames the file C:\Scripts\Test.txt to C:\Scripts\New_Name.txt:

Rename-Item c:\scripts\test.txt new_name.txt

Rename-Item Aliases

rni ren

 

2.5 Replicating (and Extending) the DIR Command

In its basic form the Get-ChildItem cmdlet provides functionality similar to the dir command. For example, if you simply type Get-ChildItem at the Windows PowerShell prompt you’ll get back information about the objects in the current location:

Directory: Microsoft.Windows PowerShell.Core\FileSystem::C:\Documents and Settings\kenmyer

Mode LastWriteTime Length Name

---- ------------- ------ ----

d---- 3/1/2006 9:03 AM Bluetooth Software d---s 5/10/2006 8:55 AM Cookies d---- 5/9/2006 2:09 PM Desktop d-r-- 5/9/2006 8:22 AM Favorites d-r-- 5/9/2006 2:24 PM My Documents d-r-- 3/1/2006 8:15 AM Start Menu d---s 3/1/2006 3:41 PM UserData d---- 3/16/2006 3:29 PM WINDOWS

That’s all well and good, but you can do a lot more with Get-ChildItem than simply list the items found in the current location. For example, in the output above you might have noticed that there wasn’t much to look at; that’s because the current location happened to be a folder that contained only a handful of subfolders. Because of that you might have found it a bit more useful if Get-ChildItem had returned not only the names of those subfolders but also the contents of those subfolders; that is, you might want a list of all the files and folders in the subfolders. No problem; just add the -recurse parameter:

Get-ChildItem - recurse

Of course, you aren’t limited to working with only the current location; in fact, you aren’t limited to working with just files and folders. Would you like to see a list of all your environment variables? Then simply pass along the path to the environment variable “drive,” like so:

Get-ChildItem env:

What about all the registry subkeys found in

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall? Why not:

Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

Note. Get-ChildItem cannot be used to retrieve information about the registry values contained within a subkey. For that you need to use the Get-ItemProperty cmdlet.

We could do this all day. For example, the -include and -exclude parameters make it easy to retrieve a specific set of items from a location. Suppose you want information about only the .txt and .log files found in the folder C:\Scripts? That’s easy:

Get-ChildItem c:\scripts\*.* -include *.txt,*.log

As you can see, we ask for all the files (*.*) found in the folder C:\Scripts. We then tack on the -include parameter, specifying two file types: *.txt and *.log. (And separating the file types using a comma). What do we get back? We get back only .txt and .log files:

Mode LastWriteTime Length Name

---- ------------- ------ ----

-a--- 4/6/2006 8:28 PM 3508 950 .Log

-a--- 5/6/2006 10:06 AM 0 Employees.txt

-a--- 5/6/2006 10:06 AM 0 Employees_NODUPL.txt

-a--- 5/6/2006 10:06 AM 0 ExcelData.txt

-a--- 3/3/2006 9:24 PM 14894 methods.txt

-a--- 4/28/2006 1:36 PM 41 new_name.txt

-a--- 3/7/2006 1:44 PM 4112 read-write.txt

-a--- 4/11/2006 11:04 AM 18 servers.txt

-a--- 5/5/2006 9:09 PM 53358 tee.txt

-a--- 4/26/2006 12:28 PM 1125 temporary_print_file.txt

-a--- 5/6/2006 10:30 PM 34184 test.log

-a--- 5/9/2006 3:17 PM 58 test.txt

-a--- 4/6/2006 10:26 PM 205 test_NODUPL.txt

-a--- 4/28/2006 1:16 PM 27 x.txt

-a--- 5/8/2006 2:39 PM 25 y.txt

If we wanted to get back everything except .txt and .log files then we’d simply use the exclude parameter instead; this parameter tells Windows PowerShell which items should not be included in the returned dataset. Here’s what the command looks like:

Get-ChildItem c:\scripts\*.* -exclude *.txt,*.log

Give it a try and see what happens.

The information returned by Get-ChildItem can also be piped into the Sort-Object cmdlet, providing a way to sort the data by in some other format. Would you rather see files sorted by size (length) than by name? Then use this command:

Get-ChildItem c:\scripts\*.* | Sort-Object length

Or, if you’d rather see the largest files listed first and the smallest files listed last, then add the -descending parameter:

Get-ChildItem c:\scripts\*.* | Sort-Object length - descending

Get-ChildItem Aliases

gci ls

dir

2.6 Retrieving a Specific Item

The Get-Item cmdlet makes it easy to retrieve a specific item (such as a file, a folder, or a registry key). Why would you want to do that? Well, for one thing, it makes it very easy to retrieve the properties of those items. For example, suppose you’d like to know the last time someone accessed the C:\scripts folder. Here’s a command that will retrieve that information:

$(Get-Item c:\scripts).lastaccesstime

In essence, we’re using Get-Item to create an object reference to C:\Scripts. That’s the reason for the unusual syntax: the command itself - Get-Item c:\scripts - is enclosed in parentheses, with a $ pasted on front. The property we’re interested in is then tacked on using standard dot notation (object.property). Want to know the number of subkeys found in HKEY_CURRENT_USER\Software? Here you go:

$(Get-Item hkcu:\software).subkeycount

Good question: how did we know that SubkeyCount was a property of a registry key? Well, to tell you the truth, we didn’t. But that’s another good use for Get-Item: we simply used Get-Item to return an object representing HKEY_CURRENT_USER\Software and then piped that object to the Get-Member cmdlet:

Get-Item hkcu:\software | Get-Member

We then left it up to Get-Member to figure out the properties of the registry key. Get-Item Aliases

gu

 

2.7 Verifying the Existence of a File or Folder

One of the primary uses of Test-Path is to verify the existence of a file or folder. For example, this command checks to see whether the file C:\Scripts\Test.txt exists:

Test-Path c:\scripts\test.txt

Test-Path returns True if the file exists, and returns False if the file does not exist.

As is usually the case with cmdlets, you can use wildcards with Test-Path. For example, this script tells you whether or not there are any .wma files in C:\Scripts:

Test-Path c:\scripts\*.wma

Did someone ask if you can you check for the existence of registry keys using Test-Path? Of course you can:

Test-Path HKCU:\Software\Microsoft\Windows\CurrentVersion

 

 

4. MANAGE FILE PERMISSION

4.1 Add, and Remove NTFS Permissions

 

Managing file and folder permissions in Windows PowerShell is not that easy, and there are numerous articles and blog posts describing how it works by using the .NET classes. This is far from being comfortable, and there is one major and one minor restriction:

  • Path length
  • Generic rights

This post introduces the NTFSSecurity module, which provides a bunch of cmdlets for managing permissions on NTFS drives. It does not use the Windows PowerShell way to access the file system, and it works around the MAX_PATH, which is 260 characters

 

Windows stores the permissions in the discretionary access control list (DACL), which is part of the Security Descriptor. The Security Descriptor also includes the system access control list (SACL), where the auditing is configured, and member information. This post is about permissions and it does not discuss the SACL or member information.

The DACL contains access control entries (ACEs) that define the permissions someone has on the object. Each ACE contains the following values:

  • Account: Who is granted or denied access. Windows does not store the user’s SamAccountName, but rather, the SID.
  • Rights: The permissions granted or denied.
  • Type: Grant or deny access.
  • IsInherited: True if the ACE is inherited from a parent object.
  • InheritanceFlags and PropagationFlags: These bits control the inheritance. The NTFSSecurity module converts the bits into something more readable that is discussed later in this post.

By default, a security descriptor on the file system inherits permissions from the parent object. Users who have full access on drive C also have full access to all subfolders if the inheritance is not disabled.

4.1.1 Reading the permissions of a single item

The first and easiest task is to retrieve the DACL from a specific file. The cmdlet that the NTFSSecurity module provides for retrieving existing permissions is Get-NTFSAccess. You can pipe a file or folder to that cmdlet or work with the Path parameter:

Get-Item D:\Data | Get-NTFSAccess

Get-NTFSAccess -Path D:\Data

The output might look like this

Image of command output

The output is grouped by the file or folder, which is important when getting the permissions of more than one object. Next to the path is information about if the file or folder inherits the permissions from the parent object. My example shows that four of the displayed ACEs have been inherited from drive D.

Some more details about the columns:

  • Account: The account that has been granted or denied access to the item. As mentioned, Windows does not store the user’s name, but rather, the SID. If the SID can be translated into the name, NTFSSecurity shows it; otherwise, the SID is displayed.
  • AccessRights: These are the actual permissions that the account has been granted or denied. The list behind this field also supports generic rights.
  • Applies to: The .NET Framework stores the inheritance information in two-bit fields: InheritanceFlags and PropagationFlags. These fields are quite difficult to interpret, so NTFSSecurity converts them into something that is known from the Windows Explorer:
  • ThisFolderOnly
  • ThisFolderSubfoldersAndFiles
  • ThisFolderAndSubfolders
  • ThisFolderAndFiles
  • SubfoldersAndFilesOnly
  • SubfoldersOnly
  • FilesOnly
  • Type: Either Allow or Deny
  • Inherited: If the ACE is inherited from the parent, this is True. The first two ACEs have been defined explicitly in the folder.
  • InhertedFrom: This column only contains information if IsInherited is True, and it indicates where the ACE is inherited from.

4.1.2 Reading the permissions of multi

You may also like...